Skip to content

Commit c73a626

Browse files
authored
Merge pull request #689 from jetstack/VC-43403-inventory-api-sha256
[VC-43403] Revert to using sha256 checksum to match latest snapshot-links API
2 parents 19fb771 + ae38261 commit c73a626

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

pkg/internal/cyberark/dataupload/dataupload.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package dataupload
33
import (
44
"bytes"
55
"context"
6-
"crypto/sha3"
6+
"crypto/sha256"
77
"crypto/x509"
8+
"encoding/base64"
89
"encoding/hex"
910
"encoding/json"
1011
"fmt"
@@ -56,20 +57,33 @@ func NewCyberArkClient(trustedCAs *x509.CertPool, baseURL string, authenticateRe
5657
}
5758

5859
// PostDataReadingsWithOptions PUTs the supplied payload to an [AWS presigned URL] which it obtains via the CyberArk inventory API.
59-
//
6060
// [AWS presigned URL]: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
61+
//
62+
// A SHA256 checksum header is included in the request, to verify that the payload
63+
// has been received intact.
64+
// Read [Checking object integrity for data uploads in Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity-upload.html),
65+
// to learn more.
66+
//
67+
// TODO(wallrj): There is a bug in the AWS backend:
68+
// [S3 Presigned PutObjectCommand URLs ignore Sha256 Hash when uploading](https://github.com/aws/aws-sdk/issues/480)
69+
// ...which means that the `x-amz-checksum-sha256` request header is optional.
70+
// If you omit that header, it is possible to PUT any data.
71+
// There is a work around listed in that issue which we have shared with the
72+
// CyberArk API team.
6173
func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, payload api.DataReadingsPost, opts Options) error {
6274
if opts.ClusterName == "" {
6375
return fmt.Errorf("programmer mistake: the cluster name (aka `cluster_id` in the config file) cannot be left empty")
6476
}
6577

6678
encodedBody := &bytes.Buffer{}
67-
checksum := sha3.New256()
68-
if err := json.NewEncoder(io.MultiWriter(encodedBody, checksum)).Encode(payload); err != nil {
79+
hash := sha256.New()
80+
if err := json.NewEncoder(io.MultiWriter(encodedBody, hash)).Encode(payload); err != nil {
6981
return err
7082
}
71-
72-
presignedUploadURL, err := c.retrievePresignedUploadURL(ctx, hex.EncodeToString(checksum.Sum(nil)), opts)
83+
checksum := hash.Sum(nil)
84+
checksumHex := hex.EncodeToString(checksum)
85+
checksumBase64 := base64.StdEncoding.EncodeToString(checksum)
86+
presignedUploadURL, err := c.retrievePresignedUploadURL(ctx, checksumHex, opts)
7387
if err != nil {
7488
return fmt.Errorf("while retrieving snapshot upload URL: %s", err)
7589
}
@@ -79,7 +93,7 @@ func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, payloa
7993
if err != nil {
8094
return err
8195
}
82-
96+
req.Header.Set("X-Amz-Checksum-Sha256", checksumBase64)
8397
version.SetUserAgent(req)
8498

8599
res, err := c.client.Do(req)
@@ -107,7 +121,7 @@ func (c *CyberArkClient) retrievePresignedUploadURL(ctx context.Context, checksu
107121

108122
request := struct {
109123
ClusterID string `json:"cluster_id"`
110-
Checksum string `json:"checksum_sha3"`
124+
Checksum string `json:"checksum_sha256"`
111125
AgentVersion string `json:"agent_version"`
112126
}{
113127
ClusterID: opts.ClusterName,

pkg/internal/cyberark/dataupload/mock.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package dataupload
22

33
import (
4-
"crypto/sha3"
5-
"encoding/hex"
4+
"crypto/sha256"
5+
"encoding/base64"
66
"encoding/json"
77
"fmt"
88
"io"
@@ -76,7 +76,7 @@ func (mds *mockDataUploadServer) handlePresignedUpload(w http.ResponseWriter, r
7676
decoder := json.NewDecoder(r.Body)
7777
var req struct {
7878
ClusterID string `json:"cluster_id"`
79-
Checksum string `json:"checksum_sha3"`
79+
Checksum string `json:"checksum_sha256"`
8080
AgentVersion string `json:"agent_version"`
8181
}
8282
decoder.DisallowUnknownFields()
@@ -112,12 +112,16 @@ func (mds *mockDataUploadServer) handlePresignedUpload(w http.ResponseWriter, r
112112
// Write response body
113113
w.WriteHeader(http.StatusOK)
114114
w.Header().Set("Content-Type", "application/json")
115-
presignedURL := mds.Server.URL + "/presigned-upload?checksum=" + req.Checksum
115+
presignedURL := mds.Server.URL + "/presigned-upload"
116116
_ = json.NewEncoder(w).Encode(struct {
117117
URL string `json:"url"`
118118
}{presignedURL})
119119
}
120120

121+
// An example of a real checksum mismatch error from the AWS API when the
122+
// request body does not match the checksum in the request header.
123+
const amzExampleChecksumError = `<Error><Code>BadDigest</Code><Message>The SHA256 you specified did not match the calculated checksum.</Message><RequestId>GBDMP09BEZ929YBK</RequestId><HostId>sFTQb9JQpfJY/t+Ctn0anBmp4lKzEGES8ttmfAmFInuJIhvaV/U+20vYaGbdtlEnExZQRV/5xo6RQqq3xItM+px/Q2AEiv1G</HostId></Error>`
124+
121125
func (mds *mockDataUploadServer) handleUpload(w http.ResponseWriter, r *http.Request, invalidJSON bool) {
122126
if r.Method != http.MethodPut {
123127
w.WriteHeader(http.StatusMethodNotAllowed)
@@ -137,11 +141,17 @@ func (mds *mockDataUploadServer) handleUpload(w http.ResponseWriter, r *http.Req
137141
return
138142
}
139143

140-
checksum := sha3.New256()
144+
amzChecksum := r.Header.Get("X-Amz-Checksum-Sha256")
145+
if amzChecksum == "" {
146+
http.Error(w, "should set x-amz-checksum-sha256 header on all requests", http.StatusInternalServerError)
147+
return
148+
}
149+
150+
checksum := sha256.New()
141151
_, _ = io.Copy(checksum, r.Body)
142152

143-
if r.URL.Query().Get("checksum") != hex.EncodeToString(checksum.Sum(nil)) {
144-
http.Error(w, "checksum is invalid", http.StatusInternalServerError)
153+
if amzChecksum != base64.StdEncoding.EncodeToString(checksum.Sum(nil)) {
154+
http.Error(w, amzExampleChecksumError, http.StatusBadRequest)
145155
}
146156

147157
w.WriteHeader(http.StatusOK)

0 commit comments

Comments
 (0)