Skip to content

Commit

Permalink
Merge branch 'master' into fix-ec2-volume-validation
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Feb 9, 2021
2 parents 842562b + fbe7e89 commit 2c9868b
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 22 deletions.
3 changes: 3 additions & 0 deletions packages/@aws-cdk/aws-ec2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ examples of things you might want to use:
> `cdk.context.json`, or use the `cdk context` command. For more information, see
> [Runtime Context](https://docs.aws.amazon.com/cdk/latest/guide/context.html) in the CDK
> developer guide.
>
> `MachineImage.genericLinux()`, `MachineImage.genericWindows()` will use `CfnMapping` in
> an agnostic stack.
## Special VPC configurations

Expand Down
54 changes: 36 additions & 18 deletions packages/@aws-cdk/aws-ec2/lib/machine-image.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as ssm from '@aws-cdk/aws-ssm';
import * as cxschema from '@aws-cdk/cloud-assembly-schema';
import { ContextProvider, Stack, Token } from '@aws-cdk/core';
import { ContextProvider, CfnMapping, Aws, Stack, Token } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { UserData } from './user-data';
import { WindowsVersion } from './windows-versions';
Expand Down Expand Up @@ -367,24 +367,33 @@ export interface GenericWindowsImageProps {
* manually specify an AMI map.
*/
export class GenericLinuxImage implements IMachineImage {
constructor(private readonly amiMap: {[region: string]: string}, private readonly props: GenericLinuxImageProps = {}) {
constructor(private readonly amiMap: { [region: string]: string }, private readonly props: GenericLinuxImageProps = {}) {
}

public getImage(scope: Construct): MachineImageConfig {
const userData = this.props.userData ?? UserData.forLinux();
const osType = OperatingSystemType.LINUX;
const region = Stack.of(scope).region;
if (Token.isUnresolved(region)) {
throw new Error('Unable to determine AMI from AMI map since stack is region-agnostic');
const mapping: { [k1: string]: { [k2: string]: any } } = {};
for (const [rgn, ami] of Object.entries(this.amiMap)) {
mapping[rgn] = { ami };
}
const amiMap = new CfnMapping(scope, 'AmiMap', { mapping });
return {
imageId: amiMap.findInMap(Aws.REGION, 'ami'),
userData,
osType,
};
}

const ami = region !== 'test-region' ? this.amiMap[region] : 'ami-12345';
if (!ami) {
const imageId = region !== 'test-region' ? this.amiMap[region] : 'ami-12345';
if (!imageId) {
throw new Error(`Unable to find AMI in AMI map: no AMI specified for region '${region}'`);
}

return {
imageId: ami,
userData: this.props.userData ?? UserData.forLinux(),
osType: OperatingSystemType.LINUX,
imageId,
userData,
osType,
};
}
}
Expand All @@ -399,20 +408,29 @@ export class GenericWindowsImage implements IMachineImage {
}

public getImage(scope: Construct): MachineImageConfig {
const userData = this.props.userData ?? UserData.forWindows();
const osType = OperatingSystemType.WINDOWS;
const region = Stack.of(scope).region;
if (Token.isUnresolved(region)) {
throw new Error('Unable to determine AMI from AMI map since stack is region-agnostic');
const mapping: { [k1: string]: { [k2: string]: any } } = {};
for (const [rgn, ami] of Object.entries(this.amiMap)) {
mapping[rgn] = { ami };
}
const amiMap = new CfnMapping(scope, 'AmiMap', { mapping });
return {
imageId: amiMap.findInMap(Aws.REGION, 'ami'),
userData,
osType,
};
}

const ami = region !== 'test-region' ? this.amiMap[region] : 'ami-12345';
if (!ami) {
const imageId = region !== 'test-region' ? this.amiMap[region] : 'ami-12345';
if (!imageId) {
throw new Error(`Unable to find AMI in AMI map: no AMI specified for region '${region}'`);
}

return {
imageId: ami,
userData: this.props.userData ?? UserData.forWindows(),
osType: OperatingSystemType.WINDOWS,
imageId,
userData,
osType,
};
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1886,6 +1886,7 @@ class LookedUpVpc extends VpcBase {
availabilityZone: vpcSubnet.availabilityZone,
subnetId: vpcSubnet.subnetId,
routeTableId: vpcSubnet.routeTableId,
ipv4CidrBlock: vpcSubnet.cidr,
}));
}
return ret;
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-ec2/lib/vpn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export class VpnConnection extends Resource implements IVpnConnection {
});
}

if (!net.isIPv4(props.ip)) {
if (!Token.isUnresolved(props.ip) && !net.isIPv4(props.ip)) {
throw new Error(`The \`ip\` ${props.ip} is not a valid IPv4 address.`);
}

Expand Down
63 changes: 63 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/machine-image.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { expect as cdkExpect, matchTemplate, MatchStyle } from '@aws-cdk/assert';
import { App, Stack } from '@aws-cdk/core';
import * as ec2 from '../lib';

Expand All @@ -11,6 +12,43 @@ beforeEach(() => {
});
});

test('can make and use a Linux image', () => {
// WHEN
const image = new ec2.GenericLinuxImage({
testregion: 'ami-1234',
});

// THEN
const details = image.getImage(stack);
expect(details.imageId).toEqual('ami-1234');
expect(details.osType).toEqual(ec2.OperatingSystemType.LINUX);
});

test('can make and use a Linux image in agnostic stack', () => {
// WHEN
app = new App();
stack = new Stack(app, 'Stack');
const image = new ec2.GenericLinuxImage({
testregion: 'ami-1234',
});

// THEN
const details = image.getImage(stack);
const expected = {
Mappings: {
AmiMap: {
testregion: {
ami: 'ami-1234',
},
},
},
};

cdkExpect(stack).to(matchTemplate(expected, MatchStyle.EXACT));
expect(stack.resolve(details.imageId)).toEqual({ 'Fn::FindInMap': ['AmiMap', { Ref: 'AWS::Region' }, 'ami'] });
expect(details.osType).toEqual(ec2.OperatingSystemType.LINUX);
});

test('can make and use a Windows image', () => {
// WHEN
const image = new ec2.GenericWindowsImage({
Expand All @@ -23,6 +61,31 @@ test('can make and use a Windows image', () => {
expect(details.osType).toEqual(ec2.OperatingSystemType.WINDOWS);
});

test('can make and use a Windows image in agnostic stack', () => {
// WHEN
app = new App();
stack = new Stack(app, 'Stack');
const image = new ec2.GenericWindowsImage({
testregion: 'ami-1234',
});

// THEN
const details = image.getImage(stack);
const expected = {
Mappings: {
AmiMap: {
testregion: {
ami: 'ami-1234',
},
},
},
};

cdkExpect(stack).to(matchTemplate(expected, MatchStyle.EXACT));
expect(stack.resolve(details.imageId)).toEqual({ 'Fn::FindInMap': ['AmiMap', { Ref: 'AWS::Region' }, 'ami'] });
expect(details.osType).toEqual(ec2.OperatingSystemType.WINDOWS);
});

test('can make and use a Generic SSM image', () => {
// WHEN
const image = new ec2.GenericSSMParameterImage('testParam', ec2.OperatingSystemType.LINUX);
Expand Down
41 changes: 41 additions & 0 deletions packages/@aws-cdk/aws-ec2/test/vpc.from-lookup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,47 @@ nodeunitShim({

test.done();
},
'subnets in imported VPC has all expected attributes'(test: Test) {
const previous = mockVpcContextProviderWith(test, {
vpcId: 'vpc-1234',
subnetGroups: [
{
name: 'Public',
type: cxapi.VpcSubnetGroupType.PUBLIC,
subnets: [
{
subnetId: 'pub-sub-in-us-east-1a',
availabilityZone: 'us-east-1a',
routeTableId: 'rt-123',
cidr: '10.100.0.0/24',
},
],
},
],
}, options => {
test.deepEqual(options.filter, {
isDefault: 'true',
});

test.equal(options.subnetGroupNameTag, undefined);
});

const stack = new Stack();
const vpc = Vpc.fromLookup(stack, 'Vpc', {
isDefault: true,
});

let subnet = vpc.publicSubnets[0];

test.equal(subnet.availabilityZone, 'us-east-1a');
test.equal(subnet.subnetId, 'pub-sub-in-us-east-1a');
test.equal(subnet.routeTable.routeTableId, 'rt-123');
test.equal(subnet.ipv4CidrBlock, '10.100.0.0/24');


restoreContextProvider(previous);
test.done();
},
},
});

Expand Down
22 changes: 21 additions & 1 deletion packages/@aws-cdk/aws-ec2/test/vpn.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, haveResource } from '@aws-cdk/assert';
import { Duration, Stack } from '@aws-cdk/core';
import { Duration, Stack, Token } from '@aws-cdk/core';
import { nodeunitShim, Test } from 'nodeunit-shim';
import { PublicSubnet, Vpc, VpnConnection } from '../lib';

Expand Down Expand Up @@ -322,4 +322,24 @@ nodeunitShim({
}));
test.done();
},
'can add a vpn connection with a Token as customer gateway ip'(test:Test) {
// GIVEN
const stack = new Stack();
const token = Token.asAny('192.0.2.1');

// WHEN
new Vpc(stack, 'VpcNetwork', {
vpnConnections: {
VpnConnection: {
ip: token as any,
},
},
});

// THEN
expect(stack).to(haveResource('AWS::EC2::CustomerGateway', {
IpAddress: '192.0.2.1',
}));
test.done();
},
});
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-kms/lib/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ abstract class KeyBase extends Resource implements IKey {
resourceArns: [this.keyArn],
resourceSelfArns: crossEnvironment ? undefined : ['*'],
};
if (this.trustAccountIdentities) {
if (this.trustAccountIdentities && !crossEnvironment) {
return iam.Grant.addToPrincipalOrResource(grantOptions);
} else {
return iam.Grant.addToPrincipalAndResource({
Expand Down
97 changes: 97 additions & 0 deletions packages/@aws-cdk/aws-kms/test/key.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,103 @@ describe('key policies', () => {
});
});

testFutureBehavior('grant for a principal in a different region', flags, cdk.App, (app) => {
const principalStack = new cdk.Stack(app, 'PrincipalStack', { env: { region: 'testregion1' } });
const principal = new iam.Role(principalStack, 'Role', {
assumedBy: new iam.AnyPrincipal(),
roleName: 'MyRolePhysicalName',
});

const keyStack = new cdk.Stack(app, 'KeyStack', { env: { region: 'testregion2' } });
const key = new kms.Key(keyStack, 'Key');

key.grantEncrypt(principal);

expect(keyStack).toHaveResourceLike('AWS::KMS::Key', {
KeyPolicy: {
Statement: arrayWith(
{
Action: [
'kms:Encrypt',
'kms:ReEncrypt*',
'kms:GenerateDataKey*',
],
Effect: 'Allow',
Principal: { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::', { Ref: 'AWS::AccountId' }, ':role/MyRolePhysicalName']] } },
Resource: '*',
},
),
Version: '2012-10-17',
},
});
expect(principalStack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: [
'kms:Encrypt',
'kms:ReEncrypt*',
'kms:GenerateDataKey*',
],
Effect: 'Allow',
Resource: '*',
},
],
Version: '2012-10-17',
},
});
});

testFutureBehavior('grant for a principal in a different account', flags, cdk.App, (app) => {
const principalStack = new cdk.Stack(app, 'PrincipalStack', { env: { account: '0123456789012' } });
const principal = new iam.Role(principalStack, 'Role', {
assumedBy: new iam.AnyPrincipal(),
roleName: 'MyRolePhysicalName',
});

const keyStack = new cdk.Stack(app, 'KeyStack', { env: { account: '111111111111' } });
const key = new kms.Key(keyStack, 'Key');

key.grantEncrypt(principal);

expect(keyStack).toHaveResourceLike('AWS::KMS::Key', {
KeyPolicy: {
Statement: [
{
// Default policy, unmodified
},
{
Action: [
'kms:Encrypt',
'kms:ReEncrypt*',
'kms:GenerateDataKey*',
],
Effect: 'Allow',
Principal: { AWS: { 'Fn::Join': ['', ['arn:', { Ref: 'AWS::Partition' }, ':iam::0123456789012:role/MyRolePhysicalName']] } },
Resource: '*',
},
],
Version: '2012-10-17',
},
});
expect(principalStack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: [
'kms:Encrypt',
'kms:ReEncrypt*',
'kms:GenerateDataKey*',
],
Effect: 'Allow',
Resource: '*',
},
],
Version: '2012-10-17',
},
});
});

testFutureBehavior('additional key admins can be specified (with imported/immutable principal)', flags, cdk.App, (app) => {
const stack = new cdk.Stack(app);
const adminRole = iam.Role.fromRoleArn(stack, 'Admin', 'arn:aws:iam::123456789012:role/TrustedAdmin');
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-s3-assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ new assets.Asset(this, 'BundledAsset', {
},
// Docker bundling fallback
image: BundlingDockerImage.fromRegistry('alpine'),
entrypoint: ['/bin/sh', '-c'],
command: ['bundle'],
},
});
Expand Down
Loading

0 comments on commit 2c9868b

Please sign in to comment.