Skip to content

Commit

Permalink
Merge branch 'master' into bump-cfnspec/v65.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Apr 5, 2022
2 parents d78b97f + 977b521 commit 2d21892
Show file tree
Hide file tree
Showing 41 changed files with 4,558 additions and 385 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/auto-approve.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ jobs:
permissions:
pull-requests: write
steps:
- uses: hmarr/auto-approve-action@v2.1.0
- uses: hmarr/auto-approve-action@v2.2.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
"VpcPublicSubnet1Subnet5C2D37C4": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.0.0/18",
"VpcId": {
"Ref": "Vpc8378EB38"
},
"AvailabilityZone": "test-region-1a",
"CidrBlock": "10.0.0.0/18",
"MapPublicIpOnLaunch": true,
"Tags": [
{
Expand Down Expand Up @@ -115,11 +115,11 @@
"VpcPublicSubnet2Subnet691E08A3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.64.0/18",
"VpcId": {
"Ref": "Vpc8378EB38"
},
"AvailabilityZone": "test-region-1b",
"CidrBlock": "10.0.64.0/18",
"MapPublicIpOnLaunch": true,
"Tags": [
{
Expand Down Expand Up @@ -180,11 +180,11 @@
"VpcPrivateSubnet1Subnet536B997A": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.128.0/18",
"VpcId": {
"Ref": "Vpc8378EB38"
},
"AvailabilityZone": "test-region-1a",
"CidrBlock": "10.0.128.0/18",
"MapPublicIpOnLaunch": false,
"Tags": [
{
Expand Down Expand Up @@ -242,11 +242,11 @@
"VpcPrivateSubnet2Subnet3788AAA1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.192.0/18",
"VpcId": {
"Ref": "Vpc8378EB38"
},
"AvailabilityZone": "test-region-1b",
"CidrBlock": "10.0.192.0/18",
"MapPublicIpOnLaunch": false,
"Tags": [
{
Expand Down Expand Up @@ -631,7 +631,11 @@
"VpcId": {
"Ref": "Vpc8378EB38"
}
}
},
"DependsOn": [
"ServiceLBPublicListenerECSGroup0CC8688C",
"ServiceLBPublicListener46709EAA"
]
}
},
"Outputs": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ class TestStack extends Stack {
port: 80,
});

listener.addTargets('Targets', {
const target = listener.addTargets('Targets', {
targets: [new targets.AlbTarget(svc.loadBalancer, 80)],
port: 80,
healthCheck: {
protocol: elbv2.Protocol.HTTP,
},
});
target.node.addDependency(svc.listener);

new CfnOutput(this, 'NlbEndpoint', { value: `http://${nlb.loadBalancerDnsName}` });
}
Expand Down
32 changes: 32 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/policy-statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ export class PolicyStatement {
private readonly condition: { [key: string]: any } = { };
private principalConditionsJson?: string;

// Hold on to those principals
private readonly _principals = new Array<IPrincipal>();

constructor(props: PolicyStatementProps = {}) {
// Validate actions
for (const action of [...props.actions || [], ...props.notActions || []]) {
Expand Down Expand Up @@ -145,6 +148,7 @@ export class PolicyStatement {
* @param principals IAM principals that will be added
*/
public addPrincipals(...principals: IPrincipal[]) {
this._principals.push(...principals);
if (Object.keys(principals).length > 0 && Object.keys(this.notPrincipal).length > 0) {
throw new Error('Cannot add \'Principals\' to policy statement if \'NotPrincipals\' have been added');
}
Expand All @@ -156,6 +160,15 @@ export class PolicyStatement {
}
}

/**
* Expose principals to allow their ARNs to be replaced by account ID strings
* in policy statements for resources policies that don't allow full account ARNs,
* such as AWS::Logs::ResourcePolicy.
*/
public get principals(): IPrincipal[] {
return [...this._principals];
}

/**
* Specify principals that is not allowed or denied access to the "NotPrincipal" section of
* a policy statement.
Expand Down Expand Up @@ -319,6 +332,25 @@ export class PolicyStatement {
this.addCondition('StringEquals', { 'sts:ExternalId': accountId });
}

/**
* Create a new `PolicyStatement` with the same exact properties
* as this one, except for the overrides
*/
public copy(overrides: PolicyStatementProps = {}) {
return new PolicyStatement({
sid: overrides.sid ?? this.sid,
effect: overrides.effect ?? this.effect,
actions: overrides.actions ?? this.action,
notActions: overrides.notActions ?? this.notAction,

principals: overrides.principals,
notPrincipals: overrides.notPrincipals,

resources: overrides.resources ?? this.resource,
notResources: overrides.notResources ?? this.notResource,
});
}

/**
* JSON-ify the policy statement
*
Expand Down
10 changes: 5 additions & 5 deletions packages/@aws-cdk/aws-lambda/test/singleton-lambda.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,17 @@ describe('singleton lambda', () => {

// WHEN
const invokeResult = singleton.grantInvoke(new iam.ServicePrincipal('events.amazonaws.com'));
const statement = stack.resolve(invokeResult.resourceStatement);
const statement = stack.resolve(invokeResult.resourceStatement?.toJSON());

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', {
Action: 'lambda:InvokeFunction',
Principal: 'events.amazonaws.com',
});
expect(statement.action).toEqual(['lambda:InvokeFunction']);
expect(statement.principal).toEqual({ Service: ['events.amazonaws.com'] });
expect(statement.effect).toEqual('Allow');
expect(statement.resource).toEqual([
expect(statement.Action).toEqual('lambda:InvokeFunction');
expect(statement.Principal).toEqual({ Service: 'events.amazonaws.com' });
expect(statement.Effect).toEqual('Allow');
expect(statement.Resource).toEqual([
{ 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'] },
{ 'Fn::Join': ['', [{ 'Fn::GetAtt': ['SingletonLambda84c0de93353f42179b0b45b6c993251a840BCC38', 'Arn'] }, ':*']] },
]);
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-logs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ const logGroup = new logs.LogGroup(this, 'LogGroup');
logGroup.grantWrite(new iam.ServicePrincipal('es.amazonaws.com'));
```

Be aware that any ARNs or tokenized values passed to the resource policy will be converted into AWS Account IDs.
This is because CloudWatch Logs Resource Policies do not accept ARNs as principals, but they do accept
Account ID strings. Non-ARN principals, like Service principals or Any princpals, are accepted by CloudWatch.

## Encrypting Log Groups

By default, log group data is always encrypted in CloudWatch Logs. You have the
Expand Down
28 changes: 26 additions & 2 deletions packages/@aws-cdk/aws-logs/lib/log-group.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import { ArnFormat, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core';
import { Arn, ArnFormat, RemovalPolicy, Resource, Stack, Token } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { LogStream } from './log-stream';
import { CfnLogGroup } from './logs.generated';
Expand Down Expand Up @@ -194,15 +194,39 @@ abstract class LogGroupBase extends Resource implements ILogGroup {
/**
* Adds a statement to the resource policy associated with this log group.
* A resource policy will be automatically created upon the first call to `addToResourcePolicy`.
*
* Any ARN Principals inside of the statement will be converted into AWS Account ID strings
* because CloudWatch Logs Resource Policies do not accept ARN principals.
*
* @param statement The policy statement to add
*/
public addToResourcePolicy(statement: iam.PolicyStatement): iam.AddToResourcePolicyResult {
if (!this.policy) {
this.policy = new ResourcePolicy(this, 'Policy');
}
this.policy.document.addStatements(statement);
this.policy.document.addStatements(statement.copy({
principals: statement.principals.map(p => this.convertArnPrincpalToAccountId(p)),
}));
return { statementAdded: true, policyDependable: this.policy };
}

private convertArnPrincpalToAccountId(principal: iam.IPrincipal) {
if (principal.principalAccount) {
// we use ArnPrincipal here because the constructor inserts the argument
// into the template without mutating it, which means that there is no
// ARN created by this call.
return new iam.ArnPrincipal(principal.principalAccount);
}

if (principal instanceof iam.ArnPrincipal) {
const parsedArn = Arn.split(principal.arn, ArnFormat.SLASH_RESOURCE_NAME);
if (parsedArn.account) {
return new iam.ArnPrincipal(parsedArn.account);
}
}

return principal;
}
}

/**
Expand Down
38 changes: 35 additions & 3 deletions packages/@aws-cdk/aws-logs/test/loggroup.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Template } from '@aws-cdk/assertions';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
import { CfnParameter, RemovalPolicy, Stack } from '@aws-cdk/core';
import { CfnParameter, Fn, RemovalPolicy, Stack } from '@aws-cdk/core';
import { LogGroup, RetentionDays } from '../lib';

describe('log group', () => {
Expand Down Expand Up @@ -364,7 +364,7 @@ describe('log group', () => {
});
});

test('can add a policy to the log group', () => {
test('when added to log groups, IAM users are converted into account IDs in the resource policy', () => {
// GIVEN
const stack = new Stack();
const lg = new LogGroup(stack, 'LogGroup');
Expand All @@ -378,11 +378,43 @@ describe('log group', () => {

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Logs::ResourcePolicy', {
PolicyDocument: '{"Statement":[{"Action":"logs:PutLogEvents","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:user/user-name"},"Resource":"*"}],"Version":"2012-10-17"}',
PolicyDocument: '{"Statement":[{"Action":"logs:PutLogEvents","Effect":"Allow","Principal":{"AWS":"123456789012"},"Resource":"*"}],"Version":"2012-10-17"}',
PolicyName: 'LogGroupPolicy643B329C',
});
});

test('imported values are treated as if they are ARNs and converted to account IDs via CFN pseudo parameters', () => {
// GIVEN
const stack = new Stack();
const lg = new LogGroup(stack, 'LogGroup');

// WHEN
lg.addToResourcePolicy(new iam.PolicyStatement({
resources: ['*'],
actions: ['logs:PutLogEvents'],
principals: [iam.Role.fromRoleArn(stack, 'Role', Fn.importValue('SomeRole'))],
}));

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Logs::ResourcePolicy', {
PolicyDocument: {
'Fn::Join': [
'',
[
'{\"Statement\":[{\"Action\":\"logs:PutLogEvents\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"',
{
'Fn::Select': [
4,
{ 'Fn::Split': [':', { 'Fn::ImportValue': 'SomeRole' }] },
],
},
'\"},\"Resource\":\"*\"}],\"Version\":\"2012-10-17\"}',
],
],
},
});
});

test('correctly returns physical name of the log group', () => {
// GIVEN
const stack = new Stack();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as path from 'path';
import * as cdk from '@aws-cdk/core';
import * as secretsmanager from '../lib';

/// !cdk-integ Integ-SecretsManager-ParsedSecretName pragma:set-context:@aws-cdk/aws-secretsmanager:parseOwnedSecretName=true

/**
* Creates several secrets, with varying names and IDs, with the parseOwnedSecretName feature flag set,
* to verify the secretName returned by `Secret.secretName` matches the `Name` returned by `DescribeSecrets`.
Expand Down Expand Up @@ -39,6 +41,9 @@ class SecretsManagerStack extends cdk.Stack {
}

const app = new cdk.App({
context: {
'@aws-cdk/aws-secretsmanager:parseOwnedSecretName': true,
},
});
new SecretsManagerStack(app, 'Integ-SecretsManager-ParsedSecretName');
app.synth();
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-ssm/lib/parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export interface StringParameterProps extends ParameterOptions {
/**
* The data type of the parameter, such as `text` or `aws:ec2:image`.
*
* @default - undefined
* @default ParameterDataType.TEXT
*/
readonly dataType?: ParameterDataType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
]
},
"Handler": "index.handler",
"Runtime": "nodejs10.x"
"Runtime": "nodejs14.x"
},
"DependsOn": [
"HelloHandlerServiceRole11EF7C63"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const stack = new cdk.Stack(app, 'CallHttpApiInteg');
const httpApi = new apigatewayv2.HttpApi(stack, 'MyHttpApi');

const handler = new lambda.Function(stack, 'HelloHandler', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: new lambda.InlineCode('exports.handler = async function(event, context) { return { statusCode: 200, body: "hello, world!" }; };'),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
]
},
"Handler": "index.handler",
"Runtime": "nodejs10.x"
"Runtime": "nodejs14.x"
},
"DependsOn": [
"HelloServiceRole1E55EA16"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const stack = new cdk.Stack(app, 'CallRestApiInteg');
const restApi = new apigateway.RestApi(stack, 'MyRestApi');

const hello = new apigateway.LambdaIntegration(new lambda.Function(stack, 'Hello', {
runtime: lambda.Runtime.NODEJS_10_X,
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: new lambda.InlineCode('exports.handler = async function(event, context) { return { statusCode: 200, body: "hello, world!" }; };'),
}));
Expand Down
Loading

0 comments on commit 2d21892

Please sign in to comment.