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

feat(ec2): security group lookup via filters #30625

Merged
merged 23 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
54ccc0d
Adding filters for lookup of security groups
jdukewich Jun 22, 2024
7bdc9a4
Linting fixes and add integration test
jdukewich Jun 22, 2024
db6985d
Integ test updates, still cannot get it to work
jdukewich Jun 29, 2024
cdb9984
Merge remote-tracking branch 'origin/main' into feat/security-group-l…
jdukewich Jun 29, 2024
285af1e
Working integ test snapshot
jdukewich Jun 30, 2024
9cdace1
Fix unit test
jdukewich Jul 1, 2024
3632c45
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 1, 2024
befdf9c
Fixing doc comments
jdukewich Jul 1, 2024
925e313
Trigger new build
jdukewich Jul 1, 2024
d5e51c0
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 1, 2024
37038d6
Fix doc typo
jdukewich Jul 2, 2024
2d7039a
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 2, 2024
29e11e7
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 3, 2024
1fba558
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 3, 2024
ce629d8
Merge branch 'main' into feat/security-group-lookup-filters
mergify[bot] Jul 8, 2024
f65e23d
Merge branch 'main' into feat/security-group-lookup-filters
mergify[bot] Jul 10, 2024
7515b82
Merge branch 'main' into feat/security-group-lookup-filters
mergify[bot] Jul 15, 2024
5867668
More coverage on integ test
jdukewich Jul 17, 2024
be1482a
Merge branch 'main' into feat/security-group-lookup-filters
jdukewich Jul 17, 2024
61ff6d1
Merge branch 'main' into feat/security-group-lookup-filters
moelasmar Aug 1, 2024
3d36c55
Merge branch 'main' into feat/security-group-lookup-filters
mergify[bot] Aug 6, 2024
76f7177
Merge branch 'main' into feat/security-group-lookup-filters
xazhao Aug 7, 2024
dd90497
Merge branch 'main' into feat/security-group-lookup-filters
mergify[bot] Aug 7, 2024
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
12 changes: 11 additions & 1 deletion packages/aws-cdk-lib/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -843,13 +843,23 @@ Alternatively, use lookup methods to import security groups if you do not know t
const sg = ec2.SecurityGroup.fromLookupByName(this, 'SecurityGroupLookup', 'security-group-name', vpc);
```

You can perform lookups based on filter conditions detailed in the [API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html).
```ts
const sg = ec2.SecurityGroup.fromLookupByFilters(this, 'SecurityGroupLookup', {
ownerId: "012345678901",
description: "my description",
tagKeys: ["tagA", "tagB"],
tags: { tagC: ["valueC", "otherValueC"], tagD: ["valueD"] }
});
```

If the security group ID is known and configuration details are unknown, use method `SecurityGroup.fromLookupById` instead. This method will lookup property `allowAllOutbound` from the current configuration of the security group.

```ts
const sg = ec2.SecurityGroup.fromLookupById(this, 'SecurityGroupLookup', 'sg-1234');
```

The result of `SecurityGroup.fromLookupByName` and `SecurityGroup.fromLookupById` operations will be written to a file called `cdk.context.json`. You must commit this file to source control so that the lookup values are available in non-privileged environments such as CI build steps, and to ensure your template builds are repeatable.
The result of `SecurityGroup.fromLookupByName`, `SecurityGroup.fromLookupById`, and `SecurityGroup.fromLookupByFilters` operations will be written to a file called `cdk.context.json`. You must commit this file to source control so that the lookup values are available in non-privileged environments such as CI build steps, and to ensure your template builds are repeatable.

### Cross Stack Connections

Expand Down
63 changes: 56 additions & 7 deletions packages/aws-cdk-lib/aws-ec2/lib/security-group.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Construct } from 'constructs';
import { Connections } from './connections';
import * as cxapi from '../../cx-api';
import * as cxschema from '../../cloud-assembly-schema';

import { Annotations, ContextProvider, IResource, Lazy, Names, Resource, ResourceProps, Stack, Token } from '../../core';
import { CfnSecurityGroup, CfnSecurityGroupEgress, CfnSecurityGroupIngress } from './ec2.generated';
import { IPeer, Peer } from './peer';
import { Port } from './port';

import { Connections } from './connections';
import { Construct } from 'constructs';
import { IVpc } from './vpc';
import * as cxschema from '../../cloud-assembly-schema';
import { Annotations, ContextProvider, IResource, Lazy, Names, Resource, ResourceProps, Stack, Token } from '../../core';
import * as cxapi from '../../cx-api';
import { Port } from './port';

const SECURITY_GROUP_SYMBOL = Symbol.for('@aws-cdk/iam.SecurityGroup');

Expand Down Expand Up @@ -387,6 +389,13 @@ export class SecurityGroup extends SecurityGroupBase {
return this.fromLookupAttributes(scope, id, { securityGroupName, vpc });
}

/**
* Look up a security group by name.
*/
jdukewich marked this conversation as resolved.
Show resolved Hide resolved
public static fromLookupByFilters(scope: Construct, id: string, filters: SecurityGroupLookupOptions) {
return this.fromLookupAttributes(scope, id, filters);
}

/**
* Import an existing security group into this app.
*
Expand Down Expand Up @@ -434,7 +443,15 @@ export class SecurityGroup extends SecurityGroupBase {
* Look up a security group.
*/
private static fromLookupAttributes(scope: Construct, id: string, options: SecurityGroupLookupOptions) {
if (Token.isUnresolved(options.securityGroupId) || Token.isUnresolved(options.securityGroupName) || Token.isUnresolved(options.vpc?.vpcId)) {
if ([
options.securityGroupId,
options.securityGroupName,
options.vpc?.vpcId,
options.description,
options.ownerId,
options.tagKeys,
options.tags,
].some(opt => Token.isUnresolved(opt))) {
throw new Error('All arguments to look up a security group must be concrete (no Tokens)');
}

Expand All @@ -444,6 +461,10 @@ export class SecurityGroup extends SecurityGroupBase {
securityGroupId: options.securityGroupId,
securityGroupName: options.securityGroupName,
vpcId: options.vpc?.vpcId,
description: options.description,
ownerId: options.ownerId,
tagKeys: options.tagKeys,
tags: options.tags,
},
dummyValue: {
securityGroupId: 'sg-12345678',
Expand Down Expand Up @@ -843,4 +864,32 @@ interface SecurityGroupLookupOptions {
* @default Don't filter on VPC
*/
readonly vpc?: IVpc;

/**
* Security group description
*
* @default Don't filter on description
*/
jdukewich marked this conversation as resolved.
Show resolved Hide resolved
readonly description?: string;

/**
* Account ID of the owner of the security group
*
* @default Don't filter on owner ID
*/
jdukewich marked this conversation as resolved.
Show resolved Hide resolved
readonly ownerId?: string;

/**
* The keys of tags assigned to the security group
*
* @default Don't filter on tag key
*/
jdukewich marked this conversation as resolved.
Show resolved Hide resolved
readonly tagKeys?: string[];

/**
* The key/value combination of a tag assigned to the security group
*
* @default Don't filter on tags
*/
jdukewich marked this conversation as resolved.
Show resolved Hide resolved
readonly tags?: Record<string, string[]>;
}
29 changes: 27 additions & 2 deletions packages/aws-cdk-lib/aws-ec2/test/security-group.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { testDeprecated } from '@aws-cdk/cdk-build-tools';
import { Template } from '../../assertions';
import { App, Intrinsic, Lazy, Stack, Token } from '../../core';
import { Peer, Port, SecurityGroup, SecurityGroupProps, Vpc } from '../lib';

import { Template } from '../../assertions';
import { testDeprecated } from '@aws-cdk/cdk-build-tools';

const SECURITY_GROUP_DISABLE_INLINE_RULES_CONTEXT_KEY = '@aws-cdk/aws-ec2.securityGroupDisableInlineRules';

describe('security group', () => {
Expand Down Expand Up @@ -596,6 +597,30 @@ describe('security group lookup', () => {

});

test('can look up a security group by filters', () => {
// GIVEN
const app = new App();
const stack = new Stack(app, 'stack', {
env: {
account: '1234',
region: 'us-east-1',
},
});

// WHEN
const securityGroup = SecurityGroup.fromLookupByFilters(stack, 'SG1', {
ownerId: "012345678901",
description: "my description",
tagKeys: ["tagA", "tagB"],
tags: { tagC: ["valueC", "otherValueC"], tagD: ["valueD"] }
});

// THEN
expect(securityGroup.securityGroupId).toEqual('sg-12345678');
expect(securityGroup.allowAllOutbound).toEqual(true);

xazhao marked this conversation as resolved.
Show resolved Hide resolved
});

test('can look up a security group and use it as a peer', () => {
// GIVEN
const app = new App();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,34 @@ export interface SecurityGroupContextQuery {
* @default - None
*/
readonly vpcId?: string;

/**
* Security group description
*
* @default - None
*/
readonly description?: string;

/**
* Account ID of the owner of the security group
*
* @default - None
*/
readonly ownerId?: string;

/**
* The keys of tags assigned to the security group
*
* @default - None
*/
readonly tagKeys?: string[];

/**
* The key/value combination of a tag assigned to the security group
*
* @default - None
*/
readonly tags?: Record<string, string[]>;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -870,13 +870,35 @@
"vpcId": {
"description": "VPC ID (Default - None)",
"type": "string"
},
"description": {
"description": "Security group description (Default - None)",
"type": "string"
},
"ownerId": {
"description": "Account ID of the owner of the security group (Default - None)",
"type": "string"
},
"tagKeys": {
"description": "The keys of tags assigned to the security group (Default - None)",
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"description": "The key/value combination of a tag assigned to the security group (Default - None)",
"$ref": "#/definitions/Record<string,string[]>"
}
},
"required": [
"account",
"region"
]
},
"Record<string,string[]>": {
"type": "object"
},
"KeyContextQuery": {
"description": "Query input for looking up a KMS Key",
"type": "object",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"36.0.0"}
{"version":"37.0.0"}
37 changes: 30 additions & 7 deletions packages/aws-cdk/lib/context-providers/security-groups.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as cxschema from '@aws-cdk/cloud-assembly-schema';
import * as cxapi from '@aws-cdk/cx-api';
import * as AWS from 'aws-sdk';
import * as cxapi from '@aws-cdk/cx-api';
import * as cxschema from '@aws-cdk/cloud-assembly-schema';

import { ContextProviderPlugin } from '../api/plugin';
import { Mode } from '../api/aws-auth/credentials';
import { SdkProvider } from '../api/aws-auth/sdk-provider';
import { ContextProviderPlugin } from '../api/plugin';

export class SecurityGroupContextProviderPlugin implements ContextProviderPlugin {
constructor(private readonly aws: SdkProvider) {
Expand All @@ -17,10 +18,6 @@ export class SecurityGroupContextProviderPlugin implements ContextProviderPlugin
throw new Error('\'securityGroupId\' and \'securityGroupName\' can not be specified both when looking up a security group');
}

if (!args.securityGroupId && !args.securityGroupName) {
throw new Error('\'securityGroupId\' or \'securityGroupName\' must be specified to look up a security group');
}

const options = { assumeRoleArn: args.lookupRoleArn };
const ec2 = (await this.aws.forEnvironment(cxapi.EnvironmentUtils.make(account, region), Mode.ForReading, options)).sdk.ec2();

Expand All @@ -37,6 +34,32 @@ export class SecurityGroupContextProviderPlugin implements ContextProviderPlugin
Values: [args.securityGroupName],
});
}
if (args.description) {
filters.push({
Name: 'description',
Values: [args.description],
});
}
if (args.tagKeys) {
filters.push({
Name: 'tag-key',
Values: args.tagKeys,
});
}
if (args.ownerId) {
filters.push({
Name: 'owner-id',
Values: [args.ownerId],
});
}
if (args.tags) {
Object.entries(args.tags).forEach(([key, values]) => {
filters.push({
Name: `tag:${key}`,
Values: values,
});
})
}

const response = await ec2.describeSecurityGroups({
GroupIds: args.securityGroupId ? [args.securityGroupId] : undefined,
Expand Down
Loading
Loading