Skip to content

Commit d521a8b

Browse files
committed
Add utility method for parsing dual-stack and fips URIs
1 parent 3e925e9 commit d521a8b

File tree

2 files changed

+296
-0
lines changed

2 files changed

+296
-0
lines changed

ecs-agent/utils/uri/uri.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package uri
15+
16+
import (
17+
"fmt"
18+
"regexp"
19+
"strings"
20+
21+
"github.com/aws/amazon-ecs-agent/ecs-agent/logger"
22+
)
23+
24+
const (
25+
// FIPSKeyword is the keyword used in FIPS endpoints
26+
// e.g. 123456789012.dkr.ecr-fips.us-west-2.amazonaws.com
27+
FIPSKeyword = "-fips"
28+
)
29+
30+
var (
31+
// ECRImagePattern matches ECR image URLs in various formats:
32+
// e.g. 123456789012.dkr.ecr-fips.us-west-2.amazonaws.com
33+
// 1234567.dkr.ecr-fips.us-iso-east-1.c2s.ic.gov/
34+
// 1234567.dkr.ecr.us-isob-east-1.sc2s.sgov.gov/
35+
// 123456789.dkr.ecr.cn-north-1.amazonaws.com.cn/
36+
// 98765432.dkr.starport.us-west-2.amazonaws.com/
37+
// 98765432.dkr.starport-fips.us-west-2.amazonaws.com/
38+
ECRImagePattern = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr\.((ecr|starport)(` + FIPSKeyword + `)?)\.([\w\-_]+)\.([\w\.\-]+).*`)
39+
40+
// ECRDualStackImagePattern matches ECR dual-stack image URLs in various formats:
41+
// e.g. 123456789012.dkr-starport-gamma.us-west-2.on.aws
42+
// 123456789012.dkr-starport-gamma-fips.us-west-2.on.aws
43+
// 123456789012.dkr-ecr.us-west-2.on.aws
44+
// 123456789012.dkr-ecr-fips.us-west-2.on.aws
45+
// 123456789012.dkr-ecr.cn-north-1.on.amazonwebservices.com.cn
46+
// 123456789012.dkr-ecr.eusc-de-east-1.amazonwebservices.eu
47+
// 123456789012.dkr-ecr.us-iso-west-1.on.aws.ic.gov
48+
// 123456789012.dkr-ecr.us-isob-east-1.on.aws.scloud
49+
// 123456789012.dkr-ecr.us-isof-south-1.on.aws.hci.ic.gov
50+
// 123456789012.dkr-ecr.eu-isoe-west-1.on.cloud-aws.adc-e.uk
51+
ECRDualStackImagePattern = regexp.MustCompile(`(^[a-zA-Z0-9][a-zA-Z0-9-_]*)\.dkr-((ecr|starport-gamma)(` + FIPSKeyword + `)?)\.([\w\-_]+)\.([\w\.\-]+).*`)
52+
)
53+
54+
func ParseURI(uri string, pattern *regexp.Regexp, dualstackPattern *regexp.Regexp) (bool, bool, bool) {
55+
matchedPattern := pattern.MatchString(uri)
56+
matchedDualstackPattern := dualstackPattern.MatchString(uri)
57+
// match either ipv4/dualstack and contains FIPSKeyword
58+
foundFips := (matchedPattern || matchedDualstackPattern) && strings.Contains(uri, FIPSKeyword)
59+
60+
logger.Info(fmt.Sprintf("URI: %s, Matched Pattern: %t, Matched Dualstack Pattern: %t, IsFIPS: %t", uri, matchedPattern, matchedDualstackPattern, foundFips))
61+
return matchedPattern, matchedDualstackPattern, foundFips
62+
}

ecs-agent/utils/uri/uri_test.go

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//go:build unit
2+
// +build unit
3+
4+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
7+
// not use this file except in compliance with the License. A copy of the
8+
// License is located at
9+
//
10+
// http://aws.amazon.com/apache2.0/
11+
//
12+
// or in the "license" file accompanying this file. This file is distributed
13+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14+
// express or implied. See the License for the specific language governing
15+
// permissions and limitations under the License.
16+
17+
package uri
18+
19+
import (
20+
"testing"
21+
)
22+
23+
func TestParseURI(t *testing.T) {
24+
testCases := []struct {
25+
name string
26+
uri string
27+
expectedMatchPattern bool
28+
expectedMatchDualstack bool
29+
expectedFIPS bool
30+
}{
31+
// Standard ECR image patterns - non-FIPS
32+
{
33+
name: "Standard ECR commercial",
34+
uri: "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-repo:latest",
35+
expectedMatchPattern: true,
36+
expectedMatchDualstack: false,
37+
expectedFIPS: false,
38+
},
39+
{
40+
name: "Standard ECR China",
41+
uri: "123456789012.dkr.ecr.cn-north-1.amazonaws.com.cn/my-repo:latest",
42+
expectedMatchPattern: true,
43+
expectedMatchDualstack: false,
44+
expectedFIPS: false,
45+
},
46+
{
47+
name: "Standard ECR GovCloud",
48+
uri: "123456789012.dkr.ecr.us-gov-west-1.amazonaws.com/my-repo:latest",
49+
expectedMatchPattern: true,
50+
expectedMatchDualstack: false,
51+
expectedFIPS: false,
52+
},
53+
{
54+
name: "Standard ECR ISO",
55+
uri: "123456789012.dkr.ecr.us-iso-east-1.c2s.ic.gov/my-repo:latest",
56+
expectedMatchPattern: true,
57+
expectedMatchDualstack: false,
58+
expectedFIPS: false,
59+
},
60+
{
61+
name: "Standard ECR ISOB",
62+
uri: "123456789012.dkr.ecr.us-isob-east-1.sc2s.sgov.gov/my-repo:latest",
63+
expectedMatchPattern: true,
64+
expectedMatchDualstack: false,
65+
expectedFIPS: false,
66+
},
67+
{
68+
name: "Standard Starport",
69+
uri: "123456789012.dkr.starport.us-west-2.amazonaws.com/my-repo:latest",
70+
expectedMatchPattern: true,
71+
expectedMatchDualstack: false,
72+
expectedFIPS: false,
73+
},
74+
75+
// Standard ECR image patterns - with FIPS
76+
{
77+
name: "Standard ECR commercial with FIPS",
78+
uri: "123456789012.dkr.ecr-fips.us-west-2.amazonaws.com/my-repo:latest",
79+
expectedMatchPattern: true,
80+
expectedMatchDualstack: false,
81+
expectedFIPS: true,
82+
},
83+
{
84+
name: "Standard ECR GovCloud with FIPS",
85+
uri: "123456789012.dkr.ecr-fips.us-gov-west-1.amazonaws.com/my-repo:latest",
86+
expectedMatchPattern: true,
87+
expectedMatchDualstack: false,
88+
expectedFIPS: true,
89+
},
90+
{
91+
name: "Standard Starport with FIPS",
92+
uri: "123456789012.dkr.starport-fips.us-west-2.amazonaws.com/my-repo:latest",
93+
expectedMatchPattern: true,
94+
expectedMatchDualstack: false,
95+
expectedFIPS: true,
96+
},
97+
98+
// Dual-stack ECR image patterns - non-FIPS
99+
{
100+
name: "Dual-stack ECR commercial",
101+
uri: "123456789012.dkr-ecr.us-west-2.on.aws/my-repo:latest",
102+
expectedMatchPattern: false,
103+
expectedMatchDualstack: true,
104+
expectedFIPS: false,
105+
},
106+
{
107+
name: "Dual-stack ECR China",
108+
uri: "123456789012.dkr-ecr.cn-north-1.on.amazonwebservices.com.cn/my-repo:latest",
109+
expectedMatchPattern: false,
110+
expectedMatchDualstack: true,
111+
expectedFIPS: false,
112+
},
113+
{
114+
name: "Dual-stack ECR ISO",
115+
uri: "123456789012.dkr-ecr.us-iso-west-1.on.aws.ic.gov/my-repo:latest",
116+
expectedMatchPattern: false,
117+
expectedMatchDualstack: true,
118+
expectedFIPS: false,
119+
},
120+
{
121+
name: "Dual-stack ECR ISOB",
122+
uri: "123456789012.dkr-ecr.us-isob-east-1.on.aws.scloud/my-repo:latest",
123+
expectedMatchPattern: false,
124+
expectedMatchDualstack: true,
125+
expectedFIPS: false,
126+
},
127+
{
128+
name: "Dual-stack ECR ISOF",
129+
uri: "123456789012.dkr-ecr.us-isof-south-1.on.aws.hci.ic.gov/my-repo:latest",
130+
expectedMatchPattern: false,
131+
expectedMatchDualstack: true,
132+
expectedFIPS: false,
133+
},
134+
{
135+
name: "Dual-stack ECR ISOE",
136+
uri: "123456789012.dkr-ecr.eu-isoe-west-1.on.cloud-aws.adc-e.uk/my-repo:latest",
137+
expectedMatchPattern: false,
138+
expectedMatchDualstack: true,
139+
expectedFIPS: false,
140+
},
141+
{
142+
name: "Dual-stack Starport Gamma",
143+
uri: "123456789012.dkr-starport-gamma.us-west-2.on.aws/my-repo:latest",
144+
expectedMatchPattern: false,
145+
expectedMatchDualstack: true,
146+
expectedFIPS: false,
147+
},
148+
149+
// Dual-stack ECR image patterns - with FIPS
150+
{
151+
name: "Dual-stack ECR commercial with FIPS",
152+
uri: "123456789012.dkr-ecr-fips.us-west-2.on.aws/my-repo:latest",
153+
expectedMatchPattern: false,
154+
expectedMatchDualstack: true,
155+
expectedFIPS: true,
156+
},
157+
{
158+
name: "Dual-stack ECR GovCloud with FIPS",
159+
uri: "123456789012.dkr-ecr-fips.us-gov-west-1.on.aws/my-repo:latest",
160+
expectedMatchPattern: false,
161+
expectedMatchDualstack: true,
162+
expectedFIPS: true,
163+
},
164+
{
165+
name: "Dual-stack Starport Gamma with FIPS",
166+
uri: "123456789012.dkr-starport-gamma-fips.us-west-2.on.aws/my-repo:latest",
167+
expectedMatchPattern: false,
168+
expectedMatchDualstack: true,
169+
expectedFIPS: true,
170+
},
171+
172+
// Edge cases and non-matching patterns
173+
{
174+
name: "Non-ECR Docker Hub image",
175+
uri: "docker.io/library/ubuntu:latest",
176+
expectedMatchPattern: false,
177+
expectedMatchDualstack: false,
178+
expectedFIPS: false,
179+
},
180+
{
181+
name: "Non-ECR private registry",
182+
uri: "private-registry.example.com/my-repo:latest",
183+
expectedMatchPattern: false,
184+
expectedMatchDualstack: false,
185+
expectedFIPS: false,
186+
},
187+
{
188+
name: "Invalid ECR URI format",
189+
uri: "123456789012.ecr.us-west-2.amazonaws.com/my-repo:latest",
190+
expectedMatchPattern: false,
191+
expectedMatchDualstack: false,
192+
expectedFIPS: false,
193+
},
194+
{
195+
name: "Invalid ECR Dual-stack URI format",
196+
uri: "123456789012.ecr-dkr.us-west-2.on.aws/my-repo:latest",
197+
expectedMatchPattern: false,
198+
expectedMatchDualstack: false,
199+
expectedFIPS: false,
200+
},
201+
{
202+
name: "URI with FIPS keyword but invalid format",
203+
uri: "ecr-fips.amazonaws.com/my-repo:latest",
204+
expectedMatchPattern: false,
205+
expectedMatchDualstack: false,
206+
expectedFIPS: false,
207+
},
208+
{
209+
name: "Empty URI",
210+
uri: "",
211+
expectedMatchPattern: false,
212+
expectedMatchDualstack: false,
213+
expectedFIPS: false,
214+
},
215+
}
216+
217+
for _, tc := range testCases {
218+
t.Run(tc.name, func(t *testing.T) {
219+
matchPattern, matchDualstack, isFIPS := ParseURI(tc.uri, ECRImagePattern, ECRDualStackImagePattern)
220+
221+
if matchPattern != tc.expectedMatchPattern {
222+
t.Errorf("Expected matchPattern to be %v, got %v for URI: %s", tc.expectedMatchPattern, matchPattern, tc.uri)
223+
}
224+
225+
if matchDualstack != tc.expectedMatchDualstack {
226+
t.Errorf("Expected matchDualstack to be %v, got %v for URI: %s", tc.expectedMatchDualstack, matchDualstack, tc.uri)
227+
}
228+
229+
if isFIPS != tc.expectedFIPS {
230+
t.Errorf("Expected isFIPS to be %v, got %v for URI: %s", tc.expectedFIPS, isFIPS, tc.uri)
231+
}
232+
})
233+
}
234+
}

0 commit comments

Comments
 (0)