Skip to content

Commit 56d5669

Browse files
committed
Support FIPS endpoints for image commands
1 parent 01bbeca commit 56d5669

File tree

5 files changed

+257
-115
lines changed

5 files changed

+257
-115
lines changed

ecs-cli/modules/cli/image/image_app.go

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,19 @@ func ImagePush(c *cli.Context) {
6565
if err != nil {
6666
logrus.Fatal("Error executing 'push': ", err)
6767
}
68-
ecrClient := ecrclient.NewClient(commandConfig)
68+
69+
var ecrClient ecrclient.Client
70+
useFips := c.Bool(flags.UseFIPSFlag)
71+
72+
if useFips {
73+
ecrClient, err = ecrclient.NewFipsClient(commandConfig)
74+
if err != nil {
75+
logrus.Fatal("Error executing 'push': ", err)
76+
}
77+
} else {
78+
ecrClient = ecrclient.NewClient(commandConfig)
79+
}
80+
6981
stsClient := stsclient.NewClient(commandConfig)
7082

7183
if err := pushImage(c, rdwr, dockerClient, ecrClient, stsClient); err != nil {
@@ -89,7 +101,19 @@ func ImagePull(c *cli.Context) {
89101
if err != nil {
90102
logrus.Fatal("Error executing 'pull': ", err)
91103
}
92-
ecrClient := ecrclient.NewClient(commandConfig)
104+
105+
var ecrClient ecrclient.Client
106+
useFips := c.Bool(flags.UseFIPSFlag)
107+
108+
if useFips {
109+
ecrClient, err = ecrclient.NewFipsClient(commandConfig)
110+
if err != nil {
111+
logrus.Fatal("Error executing 'pull': ", err)
112+
}
113+
} else {
114+
ecrClient = ecrclient.NewClient(commandConfig)
115+
}
116+
93117
stsClient := stsclient.NewClient(commandConfig)
94118

95119
if err := pullImage(c, rdwr, dockerClient, ecrClient, stsClient); err != nil {
@@ -109,7 +133,18 @@ func ImageList(c *cli.Context) {
109133
logrus.Fatal("Error executing 'images': ", err)
110134
}
111135

112-
ecrClient := ecrclient.NewClient(commandConfig)
136+
var ecrClient ecrclient.Client
137+
useFips := c.Bool(flags.UseFIPSFlag)
138+
139+
if useFips {
140+
ecrClient, err = ecrclient.NewFipsClient(commandConfig)
141+
if err != nil {
142+
logrus.Fatal("Error executing 'images': ", err)
143+
}
144+
} else {
145+
ecrClient = ecrclient.NewClient(commandConfig)
146+
}
147+
113148
if err := getImages(c, rdwr, ecrClient); err != nil {
114149
logrus.Fatal("Error executing 'images': ", err)
115150
return
@@ -118,6 +153,7 @@ func ImageList(c *cli.Context) {
118153

119154
func pushImage(c *cli.Context, rdwr config.ReadWriter, dockerClient dockerclient.Client, ecrClient ecrclient.Client, stsClient stsclient.Client) error {
120155
registryID := c.String(flags.RegistryIdFlag)
156+
121157
args := c.Args()
122158

123159
if len(args) != 1 {
@@ -253,12 +289,12 @@ func listImagesContent(w *tabwriter.Writer, info imageInfo, count int) {
253289

254290
func printImageRow(w io.Writer, info imageInfo) {
255291
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n",
256-
info.RepositoryName,
257-
info.Tag,
258-
info.ImageDigest,
259-
info.PushedAt,
260-
info.Size,
261-
)
292+
info.RepositoryName,
293+
info.Tag,
294+
info.ImageDigest,
295+
info.PushedAt,
296+
info.Size,
297+
)
262298
}
263299

264300
func getTagStatus(c *cli.Context) string {
@@ -297,17 +333,15 @@ func getECRAuth(registryURI string, registryID string,
297333
return ecrClient.GetAuthorizationToken(registryURI)
298334
}
299335

300-
func splitImageName(image string, seperatorRegExp string,
301-
format string) (registry string, repository string, tag string, err error) {
302-
336+
func splitImageName(image string, seperatorRegExp string, format string) (registry string, repository string, tag string, err error) {
303337
re := regexp.MustCompile(
304-
`^(?:((?:[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr\.[a-zA-Z0-9\-_]+\.amazonaws\.com(?:\.cn)?)/)?` + // repository uri (Optional)
305-
`([0-9a-z\-_/]+)` + // repository
306-
`(?:` + seperatorRegExp + `([0-9A-Za-z_.\-:]+))?$`) // tag (Optional)
307-
matches := re.FindStringSubmatch(image)
308-
if len(matches) == 0 {
309-
return "", "", "", fmt.Errorf("Please specify the image name in the correct format [%s]", format)
310-
}
338+
`^(?:((?:[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.ecr(\-fips)?\.[a-zA-Z0-9\-_]+\.amazonaws\.com(?:\.cn)?)/)?` + // registry uri (Optional)
339+
`([0-9a-z\-_/]+)` + // repository
340+
`(?:` + seperatorRegExp + `([0-9A-Za-z_.\-:]+))?$`) // tag or sha (Optional)
341+
matches := re.FindStringSubmatch(image)
342+
if len(matches) == 0 {
343+
return "", "", "", fmt.Errorf("Please specify the image name in the correct format [%s]", format)
344+
}
311345

312-
return matches[1], matches[2], matches[3], nil
313-
}
346+
return matches[1], matches[3], matches[4], nil
347+
}

ecs-cli/modules/cli/image/image_app_test.go

Lines changed: 137 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ const (
3838
repositoryWithSlash = "hi/repo"
3939
tag = "tag-v0.1.0"
4040
image = repository + ":" + tag
41-
registry = "registry"
42-
registryID = "123456789"
41+
registry = "https://" + registryID + ".dkr.ecr.us-west-2.amazonaws.com"
42+
registryID = "012345678912"
4343
repositoryURI = registry + "/" + repository
4444
clusterName = "defaultCluster"
4545
)
@@ -334,99 +334,142 @@ func TestImageListFail(t *testing.T) {
334334
}
335335

336336
func TestSplitImageName(t *testing.T) {
337-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(image, "[:]", "format")
338-
339-
assert.Empty(t, observedRegistryURI, "RegistryURI should be empty")
340-
assert.Equal(t, repository, observedRepo, "Repository should match")
341-
assert.Equal(t, tag, observedTag, "Tag should match")
342-
assert.NoError(t, err, "Error splitting image name")
343-
}
344-
345-
func TestSplitImageNameWithSha256(t *testing.T) {
346-
sha := "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a"
347-
expectedImage := repository + "@" + sha
348-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
349-
350-
assert.Empty(t, observedRegistryURI, "RegistryURI should be empty")
351-
assert.Equal(t, repository, observedRepo, "Repository should match")
352-
assert.Equal(t, sha, observedTag, "Tag should match")
353-
assert.NoError(t, err, "Error splitting image name")
354-
}
355-
356-
func TestSplitImageNameWithSlashInImageName(t *testing.T) {
357-
expectedImage := repositoryWithSlash
358-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
359-
360-
assert.Empty(t, observedRegistryURI, "RegistryURI should be empty")
361-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
362-
assert.Empty(t, observedTag, "Tag should be empty")
363-
assert.NoError(t, err, "Error splitting image name")
364-
}
365-
366-
func TestSplitImageNameWithSlashInImageNameAndSha256(t *testing.T) {
367-
sha := "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a"
368-
expectedImage := repositoryWithSlash + "@" + sha
369-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
370-
371-
assert.Empty(t, observedRegistryURI, "RegistryURI should be empty")
372-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
373-
assert.Equal(t, sha, observedTag, "Tag should match")
374-
assert.NoError(t, err, "Error splitting image name")
375-
}
376-
377-
func TestSplitImageNameWithSlashInImageNameAndSha256AndURI(t *testing.T) {
378-
sha := "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a"
379-
uri := "012345678912.dkr.ecr.us-east-1.amazonaws.com"
380-
expectedImage := uri + "/" + repositoryWithSlash + "@" + sha
381-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
382-
383-
assert.Equal(t, uri, observedRegistryURI, "RegistryURI should match")
384-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
385-
assert.Equal(t, sha, observedTag, "Tag should match")
386-
assert.NoError(t, err, "Error splitting image name")
387-
}
388-
389-
func TestSplitImageNameWithSlashInImageNameAndTag(t *testing.T) {
390-
expectedImage := repositoryWithSlash + ":" + tag
391-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
392-
393-
assert.Empty(t, observedRegistryURI, "RegistryURI should be empty")
394-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
395-
assert.Equal(t, tag, observedTag, "Expected tag to match")
396-
assert.NoError(t, err, "Error splitting image name")
397-
}
398-
399-
func TestSplitImageNameWithSlashInImageNameAndURI(t *testing.T) {
400-
uri := "012345678912.dkr.ecr.us-east-1.amazonaws.com"
401-
expectedImage := uri + "/" + repositoryWithSlash
402-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
403-
404-
assert.Equal(t, uri, observedRegistryURI, "RegistryURI should match")
405-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
406-
assert.Empty(t, observedTag, "Tag should be empty")
407-
assert.NoError(t, err, "Error splitting image name")
408-
}
409-
410-
func TestSplitImageNameWithSlashInImageNameAndURIAndTag(t *testing.T) {
411-
uri := "012345678912.dkr.ecr.us-east-1.amazonaws.com"
412-
expectedImage := uri + "/" + repositoryWithSlash + ":" + tag
413-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
414-
415-
assert.Equal(t, uri, observedRegistryURI, "RegistryURI should match")
416-
assert.Equal(t, repositoryWithSlash, observedRepo, "Repository should match")
417-
assert.Equal(t, tag, observedTag, "Expected tag to match")
418-
assert.NoError(t, err, "Error splitting image name")
419-
}
420-
421-
func TestSplitImageNameWithURI(t *testing.T) {
422-
uri := "012345678912.dkr.ecr.us-east-1.amazonaws.com"
423-
expectedImage := uri + "/" + repository
424-
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
337+
tests := []struct {
338+
name string
339+
uri string
340+
repository string
341+
tag string
342+
sha string
343+
}{
344+
{
345+
name: "With tag",
346+
uri: "",
347+
repository: repository,
348+
tag: tag,
349+
sha: "",
350+
},
351+
{
352+
name: "With SHA 256",
353+
uri: "",
354+
repository: repository,
355+
tag: "",
356+
sha: "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a",
357+
},
358+
{
359+
name: "With URI",
360+
uri: "012345678912.dkr.ecr.us-east-1.amazonaws.com",
361+
repository: repository,
362+
tag: "",
363+
sha: "",
364+
},
365+
{
366+
name: "Repository With a Slash in Image Name",
367+
uri: "",
368+
repository: repositoryWithSlash,
369+
tag: "",
370+
sha: "",
371+
},
372+
{
373+
name: "Repository with Slash In Image Name and Tag",
374+
uri: "",
375+
repository: repositoryWithSlash,
376+
tag: tag,
377+
sha: "",
378+
},
379+
{
380+
name: "Repository With a Slash in Image Name and SHA",
381+
uri: "",
382+
repository: repositoryWithSlash,
383+
tag: "",
384+
sha: "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a",
385+
},
386+
{
387+
name: "Repository with Slash In Image Name and URI",
388+
uri: "012345678912.dkr.ecr.us-east-1.amazonaws.com",
389+
repository: repositoryWithSlash,
390+
tag: "",
391+
sha: "",
392+
},
393+
{
394+
name: "Repository with Slash In Image Name and URI and Tag",
395+
uri: "012345678912.dkr.ecr.us-east-1.amazonaws.com",
396+
repository: repositoryWithSlash,
397+
tag: tag,
398+
sha: "",
399+
},
400+
{
401+
name: "Repository with Slash In Image Name and URI and Sha256",
402+
uri: "012345678912.dkr.ecr.us-east-1.amazonaws.com",
403+
repository: repositoryWithSlash,
404+
tag: "",
405+
sha: "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a",
406+
},
407+
{
408+
name: "Using FIPS endpoint",
409+
uri: "012345678912.dkr.ecr-fips.us-gov-west-1.amazonaws.com",
410+
repository: repository,
411+
tag: "",
412+
sha: "",
413+
},
414+
{
415+
name: "Using FIPS endpoint and slash in image name",
416+
uri: "012345678912.dkr.ecr-fips.us-gov-west-1.amazonaws.com",
417+
repository: repositoryWithSlash,
418+
tag: "",
419+
sha: "",
420+
},
421+
{
422+
name: "Using FIPS endpoint and slash in image name and tag",
423+
uri: "012345678912.dkr.ecr-fips.us-gov-west-1.amazonaws.com",
424+
repository: repositoryWithSlash,
425+
tag: tag,
426+
sha: "",
427+
},
428+
{
429+
name: "Using FIPS endpoint and slash in image name and sha",
430+
uri: "012345678912.dkr.ecr-fips.us-gov-west-1.amazonaws.com",
431+
repository: repositoryWithSlash,
432+
tag: "",
433+
sha: "sha256:0b3787ac21ffb4edbd6710e0e60f991d5ded8d8a4f558209ef5987f73db4211a",
434+
},
435+
}
436+
437+
for _, test := range tests {
438+
t.Run(test.name, func(t *testing.T) {
439+
expectedImage := test.repository
440+
441+
if test.uri != "" {
442+
expectedImage = test.uri + "/" + expectedImage
443+
}
444+
if test.tag != "" {
445+
expectedImage += ":" + test.tag
446+
}
447+
if test.sha != "" {
448+
expectedImage += "@" + test.sha
449+
}
450+
451+
observedRegistryURI, observedRepo, observedTag, err := splitImageName(expectedImage, "[:|@]", "format")
452+
assert.Equal(t, test.uri, observedRegistryURI, "RegistryURI should match")
453+
assert.Equal(t, test.repository, observedRepo, "Repository should match")
454+
455+
// Can only specify either tag or sha
456+
if test.tag != "" {
457+
assert.Equal(t, test.tag, observedTag, "Tag should match")
458+
}
459+
if test.sha != "" {
460+
assert.Equal(t, test.sha, observedTag, "SHA should match")
461+
}
462+
assert.NoError(t, err, "Error splitting image name")
463+
})
464+
}
465+
}
466+
467+
func TestSplitImageNameErrorCaseBadURI(t *testing.T) {
468+
badURI := "012345678912.dkr.ecr-blips.us-gov-west-1.amazonaws.com"
469+
invalidImage := badURI + "/" + repository
470+
_, _, _, err := splitImageName(invalidImage, "[:]", "format")
425471

426-
assert.Equal(t, uri, observedRegistryURI, "RegistryURI should match")
427-
assert.Equal(t, repository, observedRepo, "Repository should match")
428-
assert.Empty(t, observedTag, "Tag should be empty")
429-
assert.NoError(t, err, "Error splitting image name")
472+
assert.Error(t, err, "Expected error splitting image name")
430473
}
431474

432475
func TestSplitImageNameErrorCase(t *testing.T) {

0 commit comments

Comments
 (0)