Disable the Authorization header for ECR redirects.

ECR uses S3 pre-signed URLs for OCI blobs. If the ECR auth header is
added to the pre-signed URL, S3 returns a 400 error.

We address the issue by checking whether the request host matches
the one specified in the OCI configuration.

Signed-off-by: Grégoire Payen de La Garanderie <gregoire.payen.de.la.garanderie@intel.com>
This commit is contained in:
Grégoire Payen de La Garanderie
2024-04-29 23:10:04 +01:00
committed by Ashutosh Narkar
parent 92d631455f
commit d5265896de
2 changed files with 63 additions and 0 deletions
+15
View File
@@ -708,6 +708,7 @@ type awsSigningAuthPlugin struct {
AWSService string `json:"service,omitempty"`
AWSSignatureVersion string `json:"signature_version,omitempty"`
host string
ecrAuthPlugin *ecrAuthPlugin
kmsSignPlugin *awsKMSSignPlugin
@@ -827,6 +828,13 @@ func (ap *awsSigningAuthPlugin) NewClient(c Config) (*http.Client, error) {
return nil, err
}
url, err := url.Parse(c.URL)
if err != nil {
return nil, err
}
ap.host = url.Host
if ap.logger == nil {
ap.logger = c.logger
}
@@ -839,6 +847,13 @@ func (ap *awsSigningAuthPlugin) NewClient(c Config) (*http.Client, error) {
}
func (ap *awsSigningAuthPlugin) Prepare(req *http.Request) error {
if ap.host != req.URL.Host {
// Return early if the host does not match.
// This can happen when the OCI registry responded with a redirect to another host.
// For instance, ECR redirects to S3 and the ECR auth header should not be included in the S3 request.
return nil
}
switch ap.AWSService {
case "ecr":
return ap.ecrAuthPlugin.Prepare(req)
+48
View File
@@ -1586,6 +1586,54 @@ func TestECRAuthPluginRequestsAuthorizationToken(t *testing.T) {
}
}
func TestECRAuthPluginRequestsRedirection(t *testing.T) {
// Environment credentials to sign the ecr get authorization token request
t.Setenv(accessKeyEnvVar, "blablabla")
t.Setenv(secretKeyEnvVar, "tatata")
t.Setenv(awsRegionEnvVar, "us-east-1")
t.Setenv(sessionTokenEnvVar, "lalala")
ap := awsSigningAuthPlugin{
logger: logging.NewNoOpLogger(),
AWSEnvironmentCredentials: &awsEnvironmentCredentialService{},
host: "somewhere.com",
AWSService: "ecr",
}
apECR := newECRAuthPlugin(&ap)
apECR.ecr = &ecrStub{token: aws.ECRAuthorizationToken{
AuthorizationToken: "secret",
}}
ap.ecrAuthPlugin = apECR
// Request to the host specified in the plugin configuration
req := httptest.NewRequest("", "http://somewhere.com", nil)
if err := ap.Prepare(req); err != nil {
t.Errorf("ecrAuthPlugin.Prepare() = %q", err)
}
got := req.Header.Get("Authorization")
want := "Basic secret"
if got != want {
t.Errorf("req.Header.Get(\"Authorization\") = %q, want %q", got, want)
}
// Redirection to another host
req = httptest.NewRequest("", "http://somewhere-else.com", nil)
if err := ap.Prepare(req); err != nil {
t.Errorf("ecrAuthPlugin.Prepare() = %q", err)
}
got = req.Header.Get("Authorization")
want = ""
if got != want {
t.Errorf("req.Header.Get(\"Authorization\") = %q, want %q", got, want)
}
}
type ecrStub struct {
token aws.ECRAuthorizationToken
}