Improved support for Amazon EC2 Container Registry - ECR
This adds support for authenticating towards ECR in the docker builder and docker-push post-processor using them same mechanisms as in the amazon builders. I.g. access key/secret key, credentials on file, environment variables, sts tokens or IAM instance roles.
This commit is contained in:
parent
4214464065
commit
b2d9782a9e
|
@ -35,11 +35,13 @@ type Config struct {
|
|||
|
||||
// This is used to login to dockerhub to pull a private base container. For
|
||||
// pushing to dockerhub, see the docker post-processors
|
||||
Login bool
|
||||
LoginEmail string `mapstructure:"login_email"`
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
Login bool
|
||||
LoginEmail string `mapstructure:"login_email"`
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
EcrLogin bool `mapstructure:"ecr_login"`
|
||||
AwsAccessConfig `mapstructure:",squash"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -107,6 +109,10 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if c.EcrLogin && c.LoginServer == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("ECR login requires login server to be provided."))
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return nil, nil, errs
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/ecr"
|
||||
)
|
||||
|
||||
type AwsAccessConfig struct {
|
||||
AccessKey string `mapstructure:"aws_access_key"`
|
||||
SecretKey string `mapstructure:"aws_secret_key"`
|
||||
Token string `mapstructure:"aws_token"`
|
||||
}
|
||||
|
||||
// Config returns a valid aws.Config object for access to AWS services, or
|
||||
// an error if the authentication and region couldn't be resolved
|
||||
func (c *AwsAccessConfig) config(region string) (*aws.Config, error) {
|
||||
var creds *credentials.Credentials
|
||||
|
||||
config := aws.NewConfig().WithRegion(region).WithMaxRetries(11)
|
||||
sess := session.New(config)
|
||||
creds = credentials.NewChainCredentials([]credentials.Provider{
|
||||
&credentials.StaticProvider{Value: credentials.Value{
|
||||
AccessKeyID: c.AccessKey,
|
||||
SecretAccessKey: c.SecretKey,
|
||||
SessionToken: c.Token,
|
||||
}},
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(sess),
|
||||
},
|
||||
})
|
||||
return config.WithCredentials(creds), nil
|
||||
}
|
||||
|
||||
// Get a login token for Amazon AWS ECR. Returns username and password
|
||||
// or an error.
|
||||
func (c *AwsAccessConfig) EcrGetLogin(ecrUrl string) (string, string, error) {
|
||||
|
||||
exp := regexp.MustCompile("(?:http://|https://|)([0-9]*)\\.dkr\\.ecr\\.(.*)\\.amazonaws\\.com.*")
|
||||
splitUrl := exp.FindStringSubmatch(ecrUrl)
|
||||
accountId := splitUrl[1]
|
||||
region := splitUrl[2]
|
||||
|
||||
log.Println(fmt.Sprintf("Getting ECR token for account: %s in %s..", accountId, region))
|
||||
|
||||
awsConfig, err := c.config(region)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
session, err := session.NewSession(awsConfig)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("failed to create session: %s", err)
|
||||
}
|
||||
|
||||
service := ecr.New(session)
|
||||
|
||||
params := &ecr.GetAuthorizationTokenInput{
|
||||
RegistryIds: []*string{
|
||||
aws.String(accountId),
|
||||
},
|
||||
}
|
||||
resp, err := service.GetAuthorizationToken(params)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf(err.Error())
|
||||
}
|
||||
|
||||
auth, err := base64.StdEncoding.DecodeString(*resp.AuthorizationData[0].AuthorizationToken)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Error decoding ECR AuthorizationToken: %s", err)
|
||||
}
|
||||
|
||||
authParts := strings.SplitN(string(auth), ":", 2)
|
||||
log.Printf("Successfully got login for ECR: %s", ecrUrl)
|
||||
|
||||
return authParts[0], authParts[1], nil
|
||||
}
|
|
@ -21,7 +21,22 @@ func (s *StepPull) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
ui.Say(fmt.Sprintf("Pulling Docker image: %s", config.Image))
|
||||
|
||||
if config.Login {
|
||||
if config.EcrLogin {
|
||||
ui.Message("Fetching ECR credentials...")
|
||||
|
||||
username, password, err := config.EcrGetLogin(config.LoginServer)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error fetching ECR credentials: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
config.LoginUsername = username
|
||||
config.LoginPassword = password
|
||||
}
|
||||
|
||||
if config.Login || config.EcrLogin {
|
||||
ui.Message("Logging in...")
|
||||
err := driver.Login(
|
||||
config.LoginServer,
|
||||
|
|
|
@ -15,11 +15,13 @@ import (
|
|||
type Config struct {
|
||||
common.PackerConfig `mapstructure:",squash"`
|
||||
|
||||
Login bool
|
||||
LoginEmail string `mapstructure:"login_email"`
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
Login bool
|
||||
LoginEmail string `mapstructure:"login_email"`
|
||||
LoginUsername string `mapstructure:"login_username"`
|
||||
LoginPassword string `mapstructure:"login_password"`
|
||||
LoginServer string `mapstructure:"login_server"`
|
||||
EcrLogin bool `mapstructure:"ecr_login"`
|
||||
docker.AwsAccessConfig `mapstructure:",squash"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -42,6 +44,9 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if p.config.EcrLogin && p.config.LoginServer == "" {
|
||||
return fmt.Errorf("ECR login requires login server to be provided.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -60,7 +65,19 @@ func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (pac
|
|||
driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui}
|
||||
}
|
||||
|
||||
if p.config.Login {
|
||||
if p.config.EcrLogin {
|
||||
ui.Message("Fetching ECR credentials...")
|
||||
|
||||
username, password, err := p.config.EcrGetLogin(p.config.LoginServer)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
p.config.LoginUsername = username
|
||||
p.config.LoginPassword = password
|
||||
}
|
||||
|
||||
if p.config.Login || p.config.EcrLogin {
|
||||
ui.Message("Logging in...")
|
||||
err := driver.Login(
|
||||
p.config.LoginServer,
|
||||
|
|
|
@ -86,9 +86,27 @@ You must specify (only) one of `commit`, `discard`, or `export_path`.
|
|||
|
||||
### Optional:
|
||||
|
||||
- `aws_access_key` (string) - The AWS access key used to communicate with AWS.
|
||||
[Learn how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `aws_secret_key` (string) - The AWS secret key used to communicate with AWS.
|
||||
[Learn how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `aws_token` (string) - The AWS access token to use. This is different from the
|
||||
access key and secret key. If you're not sure what this is, then you
|
||||
probably don't need it. This will also be read from the `AWS_SESSION_TOKEN`
|
||||
environmental variable.
|
||||
|
||||
- `ecr_login` (boolean) - Defaults to false. If true, the builder will login in
|
||||
order to pull the image from
|
||||
[Amazon EC2 Container Registry (ECR)](https://aws.amazon.com/ecr/).
|
||||
The builder only logs in for the duration of the pull. If true
|
||||
`login_server` is required and `login`, `login_username`, and
|
||||
`login_password` will be ignored.
|
||||
|
||||
- `login` (boolean) - Defaults to false. If true, the builder will login in
|
||||
order to pull the image. The builder only logs in for the duration of
|
||||
the pull. It always logs out afterwards.
|
||||
the pull. It always logs out afterwards. For log into ECR see `ecr_login`.
|
||||
|
||||
- `login_email` (string) - The email to use to authenticate to login.
|
||||
|
||||
|
@ -237,10 +255,9 @@ shown below:
|
|||
},
|
||||
{
|
||||
"type": "docker-push",
|
||||
"login": true,
|
||||
"login_email": "none",
|
||||
"login_username": "AWS",
|
||||
"login_password": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"ecr_login": true,
|
||||
"aws_access_key": "YOUR KEY HERE",
|
||||
"aws_secret_key": "YOUR SECRET KEY HERE",
|
||||
"login_server": "https://12345.dkr.ecr.us-east-1.amazonaws.com/"
|
||||
}
|
||||
]
|
||||
|
@ -248,10 +265,7 @@ shown below:
|
|||
}
|
||||
```
|
||||
|
||||
See the
|
||||
[AWS documentation](https://docs.aws.amazon.com/AmazonECR/latest/userguide/Registries.html)
|
||||
for steps to obtain Amazon ECR registry credentials.
|
||||
|
||||
[Learn how to set Amazon AWS credentials.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
## Dockerfiles
|
||||
|
||||
|
@ -263,8 +277,8 @@ Instead, you can just provide shell scripts, Chef recipes, Puppet manifests,
|
|||
etc. to provision your Docker container just like you would a regular
|
||||
virtualized or dedicated machine.
|
||||
|
||||
While Docker has many features, Packer views Docker simply as an LXC container
|
||||
runner. To that end, Packer is able to repeatably build these LXC containers
|
||||
While Docker has many features, Packer views Docker simply as an container
|
||||
runner. To that end, Packer is able to repeatably build these containers
|
||||
using portable provisioning scripts.
|
||||
|
||||
Dockerfiles have some additional features that Packer doesn't support which are
|
||||
|
|
|
@ -18,8 +18,26 @@ pushes it to a Docker registry.
|
|||
|
||||
This post-processor has only optional configuration:
|
||||
|
||||
- `aws_access_key` (string) - The AWS access key used to communicate with AWS.
|
||||
[Learn how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `aws_secret_key` (string) - The AWS secret key used to communicate with AWS.
|
||||
[Learn how to set this.](/docs/builders/amazon.html#specifying-amazon-credentials)
|
||||
|
||||
- `aws_token` (string) - The AWS access token to use. This is different from the
|
||||
access key and secret key. If you're not sure what this is, then you
|
||||
probably don't need it. This will also be read from the `AWS_SESSION_TOKEN`
|
||||
environmental variable.
|
||||
|
||||
- `ecr_login` (boolean) - Defaults to false. If true, the post-processor
|
||||
will login in order to push the image to
|
||||
[Amazon EC2 Container Registry (ECR)](https://aws.amazon.com/ecr/).
|
||||
The post-processor only logs in for the duration of the push. If true
|
||||
`login_server` is required and `login`, `login_username`, and
|
||||
`login_password` will be ignored.
|
||||
|
||||
- `login` (boolean) - Defaults to false. If true, the post-processor will
|
||||
login prior to pushing.
|
||||
login prior to pushing. For log into ECR see `ecr_login`.
|
||||
|
||||
- `login_email` (string) - The email to use to authenticate to login.
|
||||
|
||||
|
@ -29,9 +47,9 @@ This post-processor has only optional configuration:
|
|||
|
||||
- `login_server` (string) - The server address to login to.
|
||||
|
||||
Note: When using _Docker Hub_ or _Quay_ registry servers, `login` must to be
|
||||
set to `true` and `login_email`, `login_username`, **and** `login_password`
|
||||
must to be set to your registry credentials. When using Docker Hub,
|
||||
Note: When using _Docker Hub_ or _Quay_ registry servers, `login` must to be
|
||||
set to `true` and `login_email`, `login_username`, **and** `login_password`
|
||||
must to be set to your registry credentials. When using Docker Hub,
|
||||
`login_server` can be omitted.
|
||||
|
||||
-> **Note:** If you login using the credentials above, the post-processor
|
||||
|
|
Loading…
Reference in New Issue