Skip to content

Commit 97e0973

Browse files
authored
feat(elbv2): add name validation for target group and load balancer names (#19385)
- Target group naming rules: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#cfn-elasticloadbalancingv2-targetgroup-name - Load balancer naming rules: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html#cfn-elasticloadbalancingv2-loadbalancer-name ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e727a9a commit 97e0973

File tree

4 files changed

+203
-0
lines changed

4 files changed

+203
-0
lines changed

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-load-balancer.ts

+23
Original file line numberDiff line numberDiff line change
@@ -300,4 +300,27 @@ export abstract class BaseLoadBalancer extends Resource {
300300
public removeAttribute(key: string) {
301301
this.setAttribute(key, undefined);
302302
}
303+
304+
protected validate(): string[] {
305+
const ret = super.validate();
306+
307+
// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html#cfn-elasticloadbalancingv2-loadbalancer-name
308+
const loadBalancerName = this.physicalName;
309+
if (!Token.isUnresolved(loadBalancerName) && loadBalancerName !== undefined) {
310+
if (loadBalancerName.length > 32) {
311+
ret.push(`Load balancer name: "${loadBalancerName}" can have a maximum of 32 characters.`);
312+
}
313+
if (loadBalancerName.startsWith('internal-')) {
314+
ret.push(`Load balancer name: "${loadBalancerName}" must not begin with "internal-".`);
315+
}
316+
if (loadBalancerName.startsWith('-') || loadBalancerName.endsWith('-')) {
317+
ret.push(`Load balancer name: "${loadBalancerName}" must not begin or end with a hyphen.`);
318+
}
319+
if (!/^[0-9a-z-]+$/i.test(loadBalancerName)) {
320+
ret.push(`Load balancer name: "${loadBalancerName}" must contain only alphanumeric characters or hyphens.`);
321+
}
322+
}
323+
324+
return ret;
325+
}
303326
}

packages/@aws-cdk/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts

+14
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,20 @@ export abstract class TargetGroupBase extends CoreConstruct implements ITargetGr
339339
ret.push("'vpc' is required for a non-Lambda TargetGroup");
340340
}
341341

342+
// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-targetgroup.html#cfn-elasticloadbalancingv2-targetgroup-name
343+
const targetGroupName = this.resource.name;
344+
if (!cdk.Token.isUnresolved(targetGroupName) && targetGroupName !== undefined) {
345+
if (targetGroupName.length > 32) {
346+
ret.push(`Target group name: "${targetGroupName}" can have a maximum of 32 characters.`);
347+
}
348+
if (targetGroupName.startsWith('-') || targetGroupName.endsWith('-')) {
349+
ret.push(`Target group name: "${targetGroupName}" must not begin or end with a hyphen.`);
350+
}
351+
if (!/^[0-9a-z-]+$/i.test(targetGroupName)) {
352+
ret.push(`Target group name: "${targetGroupName}" must contain only alphanumeric characters or hyphens.`);
353+
}
354+
}
355+
342356
return ret;
343357
}
344358
}

packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/load-balancer.test.ts

+90
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,96 @@ describe('tests', () => {
241241
});
242242
});
243243

244+
test('loadBalancerName unallowed: more than 32 characters', () => {
245+
// GIVEN
246+
const app = new cdk.App();
247+
const stack = new cdk.Stack(app);
248+
const vpc = new ec2.Vpc(stack, 'Stack');
249+
250+
// WHEN
251+
new elbv2.NetworkLoadBalancer(stack, 'NLB', {
252+
loadBalancerName: 'a'.repeat(33),
253+
vpc,
254+
});
255+
256+
// THEN
257+
expect(() => {
258+
app.synth();
259+
}).toThrow('Load balancer name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" can have a maximum of 32 characters.');
260+
});
261+
262+
test('loadBalancerName unallowed: starts with "internal-"', () => {
263+
// GIVEN
264+
const app = new cdk.App();
265+
const stack = new cdk.Stack(app);
266+
const vpc = new ec2.Vpc(stack, 'Stack');
267+
268+
// WHEN
269+
new elbv2.NetworkLoadBalancer(stack, 'NLB', {
270+
loadBalancerName: 'internal-myLoadBalancer',
271+
vpc,
272+
});
273+
274+
// THEN
275+
expect(() => {
276+
app.synth();
277+
}).toThrow('Load balancer name: "internal-myLoadBalancer" must not begin with "internal-".');
278+
});
279+
280+
test('loadBalancerName unallowed: starts with hyphen', () => {
281+
// GIVEN
282+
const app = new cdk.App();
283+
const stack = new cdk.Stack(app);
284+
const vpc = new ec2.Vpc(stack, 'Stack');
285+
286+
// WHEN
287+
new elbv2.NetworkLoadBalancer(stack, 'NLB', {
288+
loadBalancerName: '-myLoadBalancer',
289+
vpc,
290+
});
291+
292+
// THEN
293+
expect(() => {
294+
app.synth();
295+
}).toThrow('Load balancer name: "-myLoadBalancer" must not begin or end with a hyphen.');
296+
});
297+
298+
test('loadBalancerName unallowed: ends with hyphen', () => {
299+
// GIVEN
300+
const app = new cdk.App();
301+
const stack = new cdk.Stack(app);
302+
const vpc = new ec2.Vpc(stack, 'Stack');
303+
304+
// WHEN
305+
new elbv2.NetworkLoadBalancer(stack, 'NLB', {
306+
loadBalancerName: 'myLoadBalancer-',
307+
vpc,
308+
});
309+
310+
// THEN
311+
expect(() => {
312+
app.synth();
313+
}).toThrow('Load balancer name: "myLoadBalancer-" must not begin or end with a hyphen.');
314+
});
315+
316+
test('loadBalancerName unallowed: unallowed characters', () => {
317+
// GIVEN
318+
const app = new cdk.App();
319+
const stack = new cdk.Stack(app);
320+
const vpc = new ec2.Vpc(stack, 'Stack');
321+
322+
// WHEN
323+
new elbv2.NetworkLoadBalancer(stack, 'NLB', {
324+
loadBalancerName: 'my load balancer',
325+
vpc,
326+
});
327+
328+
// THEN
329+
expect(() => {
330+
app.synth();
331+
}).toThrow('Load balancer name: "my load balancer" must contain only alphanumeric characters or hyphens.');
332+
});
333+
244334
test('imported network load balancer with no vpc specified throws error when calling addTargets', () => {
245335
// GIVEN
246336
const stack = new cdk.Stack();

packages/@aws-cdk/aws-elasticloadbalancingv2/test/nlb/target-group.test.ts

+76
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,82 @@ describe('tests', () => {
144144
}).toThrow(/Health check interval '5' not supported. Must be one of the following values '10,30'./);
145145
});
146146

147+
test('targetGroupName unallowed: more than 32 characters', () => {
148+
// GIVEN
149+
const app = new cdk.App();
150+
const stack = new cdk.Stack(app);
151+
const vpc = new ec2.Vpc(stack, 'Stack');
152+
153+
// WHEN
154+
new elbv2.NetworkTargetGroup(stack, 'Group', {
155+
vpc,
156+
port: 80,
157+
targetGroupName: 'a'.repeat(33),
158+
});
159+
160+
// THEN
161+
expect(() => {
162+
app.synth();
163+
}).toThrow('Target group name: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" can have a maximum of 32 characters.');
164+
});
165+
166+
test('targetGroupName unallowed: starts with hyphen', () => {
167+
// GIVEN
168+
const app = new cdk.App();
169+
const stack = new cdk.Stack(app);
170+
const vpc = new ec2.Vpc(stack, 'Stack');
171+
172+
// WHEN
173+
new elbv2.NetworkTargetGroup(stack, 'Group', {
174+
vpc,
175+
port: 80,
176+
targetGroupName: '-myTargetGroup',
177+
});
178+
179+
// THEN
180+
expect(() => {
181+
app.synth();
182+
}).toThrow('Target group name: "-myTargetGroup" must not begin or end with a hyphen.');
183+
});
184+
185+
test('targetGroupName unallowed: ends with hyphen', () => {
186+
// GIVEN
187+
const app = new cdk.App();
188+
const stack = new cdk.Stack(app);
189+
const vpc = new ec2.Vpc(stack, 'Stack');
190+
191+
// WHEN
192+
new elbv2.NetworkTargetGroup(stack, 'Group', {
193+
vpc,
194+
port: 80,
195+
targetGroupName: 'myTargetGroup-',
196+
});
197+
198+
// THEN
199+
expect(() => {
200+
app.synth();
201+
}).toThrow('Target group name: "myTargetGroup-" must not begin or end with a hyphen.');
202+
});
203+
204+
test('targetGroupName unallowed: unallowed characters', () => {
205+
// GIVEN
206+
const app = new cdk.App();
207+
const stack = new cdk.Stack(app);
208+
const vpc = new ec2.Vpc(stack, 'Stack');
209+
210+
// WHEN
211+
new elbv2.NetworkTargetGroup(stack, 'Group', {
212+
vpc,
213+
port: 80,
214+
targetGroupName: 'my target group',
215+
});
216+
217+
// THEN
218+
expect(() => {
219+
app.synth();
220+
}).toThrow('Target group name: "my target group" must contain only alphanumeric characters or hyphens.');
221+
});
222+
147223
test.each([elbv2.Protocol.UDP, elbv2.Protocol.TCP_UDP, elbv2.Protocol.TLS])(
148224
'Throws validation error, when `healthCheck` has `protocol` set to %s',
149225
(protocol) => {

0 commit comments

Comments
 (0)