Skip to content

Commit

Permalink
Disable the Authorization header for ECR redirects.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
gdlg authored and ashutosh-narkar committed May 9, 2024
1 parent 92d6314 commit d526589
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
15 changes: 15 additions & 0 deletions plugins/rest/auth.go
Expand Up @@ -708,6 +708,7 @@ type awsSigningAuthPlugin struct {
AWSService string `json:"service,omitempty"`
AWSSignatureVersion string `json:"signature_version,omitempty"`

host string
ecrAuthPlugin *ecrAuthPlugin
kmsSignPlugin *awsKMSSignPlugin

Expand Down Expand Up @@ -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
}
Expand All @@ -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)
Expand Down
48 changes: 48 additions & 0 deletions plugins/rest/aws_test.go
Expand Up @@ -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
}
Expand Down

0 comments on commit d526589

Please sign in to comment.