diff --git a/controllers/bsl.go b/controllers/bsl.go index 06fdab629b..bc05ae039d 100644 --- a/controllers/bsl.go +++ b/controllers/bsl.go @@ -221,6 +221,18 @@ func (r *DPAReconciler) updateBSLFromSpec(bsl *velerov1.BackupStorageLocation, d registryDeployment = "False" } } + // The AWS SDK expects the server providing S3 blobs to remove default ports + // (80 for HTTP and 443 for HTTPS) before calculating a signature, and not + // all S3-compatible services do this. Remove the ports here to avoid 403 + // errors from mismatched signatures. + if bslSpec.Provider == "aws" { + s3Url := bslSpec.Config["s3Url"] + if len(s3Url) > 0 { + if s3Url, err = common.StripDefaultPorts(s3Url); err == nil { + bslSpec.Config["s3Url"] = s3Url + } + } + } bsl.Labels = map[string]string{ "app.kubernetes.io/name": common.OADPOperatorVelero, "app.kubernetes.io/instance": bsl.Name, diff --git a/pkg/common/common.go b/pkg/common/common.go index edefa003f3..43854baf99 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -2,8 +2,11 @@ package common import ( "fmt" + "net/http" + "net/url" "os" + "github.com/aws/aws-sdk-go/aws/request" "github.com/vmware-tanzu/velero/pkg/restore" corev1 "k8s.io/api/core/v1" ) @@ -198,3 +201,18 @@ func CCOWorkflow() bool { } return false } + +// StripDefaultPorts removes port 80 from HTTP URLs and 443 from HTTPS URLs. +// Defer to the actual AWS SDK implementation to match its behavior exactly. +func StripDefaultPorts(fromUrl string) (string, error) { + u, err := url.Parse(fromUrl) + if err != nil { + return "", err + } + r := http.Request{ + URL: u, + } + request.SanitizeHostForHeader(&r) + r.URL.Host = r.Host + return r.URL.String(), nil +}