-
Notifications
You must be signed in to change notification settings - Fork 25
Use sigv4 for sending data to s3 #772
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
Conversation
b2bfea1 to
0709b68
Compare
ed5a68d to
90d4cd0
Compare
Just using sigv4 shouldn't require changes, but the backend made a couple of extra requirements alongside changing to sigv4 - requiring headers for tagging and encryption. Signed-off-by: Ashley Davis <ashley.davis@cyberark.com>
SgtCoDFish
left a comment
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.
Minor self review
| // TODO(wallrj): There is a bug in the AWS backend: | ||
| // [S3 Presigned PutObjectCommand URLs ignore Sha256 Hash when uploading](https://github.com/aws/aws-sdk/issues/480) | ||
| // ...which means that the `x-amz-checksum-sha256` request header is optional. | ||
| // If you omit that header, it is possible to PUT any data. | ||
| // There is a work around listed in that issue which we have shared with the | ||
| // CyberArk API team. |
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.
nb: switching to sigv4 should fix this, so I removed the comment.
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 verified that S3 does now reject a payload that differs from the checksum , by modifying the code to send a different body
modified internal/cyberark/dataupload/dataupload.go
@@ -130,7 +130,7 @@ func (c *CyberArkClient) PutSnapshot(ctx context.Context, snapshot Snapshot) err
}
// The snapshot-links endpoint returns an AWS presigned URL which only supports the PUT verb.
- req, err := http.NewRequestWithContext(ctx, http.MethodPut, presignedUploadURL, encodedBody)
+ req, err := http.NewRequestWithContext(ctx, http.MethodPut, presignedUploadURL, bytes.NewBufferString("foo"))
if err != nil {
return err
}
$ HTTPS_PROXY=localhost:8080 go test ./internal/cyberark -run TestCyberArkClient_PutSnapshot_RealAPI -v -count 1 -args -testing.v 6
=== RUN TestCyberArkClient_PutSnapshot_RealAPI
client_test.go:68: This test runs against a live service and has been known to flake. If you see timeout issues it's possible that the test is flaking and it could be unrelated to your changes.
roundtripper_log.go:40: I0212 09:38:17.751277] outgoing http request succeeded method="POST" uri="https://anb5751.id.integration-cyberark.cloud/Security/StartAuthentication" status="200 OK" duration="864.907164ms"
identity.go:296: I0212 09:38:17.753307] made successful request to StartAuthentication source="Identity.doStartAuthentication" summary="NewPackage"
roundtripper_log.go:40: I0212 09:38:18.290674] outgoing http request succeeded method="POST" uri="https://anb5751.id.integration-cyberark.cloud/Security/AdvanceAuthentication" status="200 OK" duration="536.940608ms"
identity.go:406: I0212 09:38:18.293336] successfully completed AdvanceAuthentication request to CyberArk Identity; login complete username="github-jetstack-secure-tests@cyberark.cloud.420375"
roundtripper_log.go:40: I0212 09:38:20.618176] outgoing http request succeeded method="POST" uri="https://tlskp-test.inventory.integration-cyberark.cloud/api/ingestions/kubernetes/snapshot-links" status="200 OK" duration="2.323008336s"
roundtripper_log.go:40: I0212 09:38:21.599913] outgoing http request succeeded method="PUT" uri="https://snapshots-marshmallow-a1b2c3d4-integration.s3.amazonaws.com/k8s_snapshot/8f08a102-58ca-49cd-960e-debc5e0d3cd4/ffffffff-ffff-ffff-ffff-ffffffffffff/20260212_093819_024.snapshot?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAR53UX6ITGLFJ3X7O%2F20260212%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260212T093820Z&X-Amz-SignedHeaders=host%3Bx-amz-checksum-sha256%3Bx-amz-server-side-encryption%3Bx-amz-tagging&X-Amz-Expires=300&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEAoaCXVzLWVhc3QtMSJGMEQCIFYTedh%2FtPURHsWllUDXtmFzYLBl2ACZJZZscIxApSPuAiBZ9%2Big%2BRIpBjxkcbsRB%2F9u9zNjRLQCDhdCfK%2B%2BLku3DiqmBAjT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDEzMjg1MTk1NDIxNCIM8ShUS54FDYcNlFzSKvoDfSXbVrv1TG33VxVBECBPhw1eUx8OUIcrquWueS%2F8oKFkp9NWzOtl8CyLA9UXldxup%2BtG4MEevYkwxYJR2YUGnowCSKYwQ9MSM7HecXOoEYiv2R3Limw7FJ32TqoswlnVseDrMvvcBRIT0h5Iriw1MqEQgTpeCm8L3jWoPtOuA7Cl0faL1VMiVM%2FmTfB4SmIeUEuHj8dC1Vh96x6%2B9PWQPKbAxKrJJhTxGJgaRp7r2S3v5kqsw94wvU6T56km597okOsAWZS%2FVswQNwZkjTDRgr1qamefBRsUR6S54kY7oUxHmNvffL%2BshAUrWwEePR0eb%2Fi%2BZZ4bPJEX1lqHZlpHVh5E9SexGbNHkmPqrU4Uz4NM3%2BZ9QBHBOYrjE0Wl3eZbUzn%2FPXfF%2BXAp0pzrDyF2eTF00zDn9%2FuSB1SCpRBh6mLP490E%2BilXFFc25x0Km8jpVMEruDjH77UhVIoLdhKz%2B8NYpZwvfDkHW%2F82e5JuWwUv8ON7Ax%2FC55%2B13m7IogN2WgiOAjHun2gHqXq%2FyQDxi%2BMNmOxUEstaixlMcc4uyl4GMZId%2FpcD7avWeUrUjmiEiIGUjyJCeOnsWTWnEAo2hVGDee4q2cBUz515gpZNbp6NHJ6cqkDOMl20SYWwKuoFWPQkDZD0Lm8bctuhv%2BeqrOOSNOdo7lcnm3gwhr%2B2zAY6ngEtm1mWVekgk1uDzsiSUH4iC50qabbQkgHJ87n5uvW944G5wCahkqtK8s0KFM02c5ZgrPZDsPcNXCh%2FDuiVkJxSybpKFkrG2MGjnCG%2FyLfkXGNYmiNNZCj6eVJ7cbEIWRv4GwVStA2BZbPNNqFNlNYtuXNEOQHAi4g5ado5T2eh0uC1VCvjwJqLWRmSvzVXfagptFILYuquy2JolEUFyQ%3D%3D&X-Amz-Signature=38dc054859815b32ce4ca81e41e16dd5dc87e0e5fa2459c9fbbaf5dc7717a9d6" status="400 Bad Request" duration="949.808567ms"
client_test.go:94:
Error Trace: /home/richard/projects/jetstack/jetstack-secure/internal/cyberark/client_test.go:94
Error: Received unexpected error:
received response with status code 400: <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>BadDigest</Code><Message>The SHA256 you specified did not match the calculated checksum.</Message><RequestId>4MPWDH55H9VP8EYD</RequestId><HostId>+tbF2v0ebSHEQuipi9nY0qWgv5ZIYmY8gWT5nOnBdvGb44o82qDBxWOw4S60xg/V1ku1ojVROA4=</HostId></Error>
Test: TestCyberArkClient_PutSnapshot_RealAPI
--- FAIL: TestCyberArkClient_PutSnapshot_RealAPI (6.03s)
FAIL
FAIL github.com/jetstack/preflight/internal/cyberark 6.416s
FAIL
| username, err := c.authenticateRequest(req) | ||
| if err != nil { | ||
| return "", "", fmt.Errorf("failed to authenticate request: %s", err) | ||
| } |
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.
note: since the username is inherently tied to the token, I wanted to ensure that the two were only able to be pulled simultaneously while the lock was held.
In the current codebase I can't really see how the username could desync from the token if we passed it around some other way but I think it's best to make the change now.
I assume it's possible to get the username from the token itself if we parse it but I'd rather keep it as a black-box and not depend on any implementation details of it.
Signed-off-by: Ashley Davis <ashley.davis@cyberark.com>
| switch r.URL.Path { | ||
| case apiPathSnapshotLinks: | ||
| mds.handleSnapshotLinks(w, r) | ||
| return | ||
| case "/presigned-upload": | ||
| mds.handlePresignedUpload(w, r) | ||
| return | ||
| default: | ||
| w.WriteHeader(http.StatusNotFound) | ||
| } |
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.
note: I wanted to use ServeMux for this to track variables across calls, so I reworked this a bit
wallrj-cyberark
left a comment
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 good @SgtCoDFish
I ran one of the integration tests locally, via mitmproxy, and observed the new tagging headers:
$ HTTPS_PROXY=localhost:8080 go test ./internal/cyberark -v --testing.v 6
X-Amz-Tagging: agent_version=development&tenant_id=8f08a102-58ca-49cd-960e-debc5e0d3cd4&upload_type=k8s_snapshot&uploader_id=ffffffff-ffff-ffff-ffff-ffffffffffff&username=g
ithub-jetstack-secure-tests%40cyberark.cloud.420375&vendor=k8s
Here's the full copilot review FYI: https://gist.github.com/wallrj-cyberark/da6a2188c37d414a61ace5d345f0ebaa
|
|
||
| // Write response body | ||
| w.WriteHeader(http.StatusOK) | ||
| w.Header().Set("Content-Type", "application/json") |
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.
Copilot spotted a problem in this existing code. It thinks that Header.Set MUST come before any WriteHeader otherwise it is discarded.
5. Mock server: w.WriteHeader before w.Header().Set
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")In Go's net/http, headers must be set before calling WriteHeader. After WriteHeader is called, setting headers has no effect. This is a bug in the mock (though it may not affect test correctness since JSON decoding doesn't depend on Content-Type).
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.
Good shout, I'll address that in #770 since that'll need a rebase once this merges!
So far, I believe only our e2e test tenant is feature gated to have this enabled, but the implication of that is that our tests fail. The long term goal is to have this enabled everywhere.
Just changing to sigv4 shouldn't require changes to the agent but the backend added a couple of extra requirements alongside changing to sigv4 - i.e. requiring headers for tagging and encryption.
This PR also adds tests for those new headers.
Backwards compat: the backend will handle backwards compatibility (i.e. they'll allow older version of the agent to not send the required headers for some period of time, to give people time to update).