Skip to content
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

Create standalone docker file & allow it to be used for retrieving credentials manually #72

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

FROM golang:1.9
FROM golang:1.9-alpine3.6 AS builder

WORKDIR /go/src/github.com/awslabs/amazon-ecr-credential-helper
COPY ecr-login /go/src/github.com/awslabs/amazon-ecr-credential-helper/ecr-login

COPY . .
RUN env CGO_ENABLED=0 go install -installsuffix "static" \
github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login

CMD make
FROM alpine:3.6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any particular reason you need a full Alpine container instead of a scratch container? The executable is statically-linked, so the only thing that should be necessary at that point is a CA certificate bundle rather than the rest of the Linux userland.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internally we used this container to run scripts within our CI so we found it useful to have basic UNIX utilities. Alpine overhead is around 4 MB which seemed reasonable to me. Also I am not sure how to just add the CA certificate bundle. If you have some pointers, I shall be happy to change this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my preference would be for a scratch container so that we don't need to worry about updating the base layer. You can see an example that builds a scratch container with a CA certificate bundle here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I shall update the Dockerfile to use scratch base.


RUN apk add --no-cache ca-certificates

COPY --from=builder /go/bin/docker-credential-ecr-login /usr/local/bin/docker-credential-ecr-login

ENTRYPOINT [ "/usr/local/bin/docker-credential-ecr-login" ]
CMD [ "eval" ]
20 changes: 20 additions & 0 deletions build.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

FROM golang:1.9

WORKDIR /go/src/github.com/awslabs/amazon-ecr-credential-helper

COPY . .

CMD make
39 changes: 38 additions & 1 deletion ecr-login/cli/docker-credential-ecr-login/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
package main

import (
"fmt"
"os"

ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
"github.com/awslabs/amazon-ecr-credential-helper/ecr-login/api"
"github.com/awslabs/amazon-ecr-credential-helper/ecr-login/config"
Expand All @@ -24,5 +27,39 @@ import (
func main() {
defer log.Flush()
config.SetupLogger()
credentials.Serve(ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}})
helper := ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}}
if len(os.Args) > 1 && os.Args[1] == "eval" {
evalCommand(helper)
} else {
credentials.Serve(helper)
}
}

func evalCommand(helper credentials.Helper) {
server, err := parseArgs(helper)
if err == nil {
var user, token string
user, token, err = helper.Get(server)
if err == nil {
fmt.Printf("docker login -u %s -p %s %s\n", user, token, server)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little leery of doing this. Docker has already changed the arguments that it accepts for docker login; it used to be that --email was required, but now providing --email fails. You can see the challenge that we had with the AWS CLI and adapting it here: aws/aws-cli#1926.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know; the latest version of docker is recommending to pass the arguments over stdin using --password-stdin flag. It is very annoying that the CLI is not kept backwards compatible.

My primary use case was running eval $(docker run --rm -e AWS_REGION=us-east-1 dolbylabs/amazon-ecr-credential-helper) in our normal EC2 instances on startup to be able to login to ECR. Since we pull our images only at startup, this was sufficient.

The only other alternative is to vendor the moby/client and call RegistryLogin() function directly. I can make this change if you no not mind the extra vendor dependencies. I can still use the resulting image by bind mounting docker socket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that using moby/client/RegistryLogin() with the Docker socket will actually cause the ~/.docker/config.json file to be written since the Docker socket controls the Docker daemon and not the client.

I think your use-case makes sense, but I'm still concerned as docker login does change (and the change you mentioned I didn't even know about until you said it here!). Maybe instead of just calling it eval, we can encode the expected Docker CLI version in the name of the command somehow? Something like eval-1.11 so that it produces a docker login command without --email?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can change eval to eval-1.11 so it is more explicit. I can also add eval-17.06 with following code:
fmt.Printf("echo %s | docker login --password-stdin -u %s %s", token, user, server)

It will help to silence warnings from docker.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email flag for docker login has been optional since docker v1.4. So I do not think we need to worry about the email flag. I can add --password-stdin flag to eval command to handle the new way and add -e flag without options to output email.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know offhand, but I'm pretty sure email was still required as of Docker 1.9. I think I would prefer separate commands that correspond to the first version where the Docker CLI expected the invocation.

}
}
if err != nil {
fmt.Fprintf(os.Stdout, "%v\n", err)
os.Exit(1)
}
}

func parseArgs(helper credentials.Helper) (string, error) {
if len(os.Args) > 2 {
return os.Args[2], nil
}
servers, err := helper.List()
if err == nil {
for k := range servers {
return k, nil
}
return "", fmt.Errorf("No default ECR servers found")
}
return "", err
}