Skip to content

Commit

Permalink
Merge branch 'master' into huijbers/break-policy-limit
Browse files Browse the repository at this point in the history
  • Loading branch information
rix0rrr authored May 25, 2022
2 parents 0b5d853 + 5d2501b commit 2ec115b
Show file tree
Hide file tree
Showing 151 changed files with 2,787 additions and 3,091 deletions.
18 changes: 7 additions & 11 deletions packages/@aws-cdk/aws-codepipeline/lib/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ export class Pipeline extends PipelineBase {
private readonly crossAccountKeys: boolean;
private readonly enableKeyRotation?: boolean;
private readonly reuseCrossRegionSupportStacks: boolean;
private readonly codePipeline: CfnPipeline;

constructor(scope: Construct, id: string, props: PipelineProps = {}) {
super(scope, id, {
Expand Down Expand Up @@ -426,7 +427,7 @@ export class Pipeline extends PipelineBase {
assumedBy: new iam.ServicePrincipal('codepipeline.amazonaws.com'),
});

const codePipeline = new CfnPipeline(this, 'Resource', {
this.codePipeline = new CfnPipeline(this, 'Resource', {
artifactStore: Lazy.any({ produce: () => this.renderArtifactStoreProperty() }),
artifactStores: Lazy.any({ produce: () => this.renderArtifactStoresProperty() }),
stages: Lazy.any({ produce: () => this.renderStages() }),
Expand All @@ -437,11 +438,11 @@ export class Pipeline extends PipelineBase {
});

// this will produce a DependsOn for both the role and the policy resources.
codePipeline.node.addDependency(this.role);
this.codePipeline.node.addDependency(this.role);

this.artifactBucket.grantReadWrite(this.role);
this.pipelineName = this.getResourceNameAttribute(codePipeline.ref);
this.pipelineVersion = codePipeline.attrVersion;
this.pipelineName = this.getResourceNameAttribute(this.codePipeline.ref);
this.pipelineVersion = this.codePipeline.attrVersion;
this.crossRegionBucketsPassed = !!props.crossRegionReplicationBuckets;

for (const [region, replicationBucket] of Object.entries(props.crossRegionReplicationBuckets || {})) {
Expand Down Expand Up @@ -724,13 +725,8 @@ export class Pipeline extends PipelineBase {
}

// the pipeline role needs assumeRole permissions to the action role
if (actionRole) {
this.role.addToPrincipalPolicy(new iam.PolicyStatement({
actions: ['sts:AssumeRole'],
resources: [actionRole.roleArn],
}));
}

const grant = actionRole?.grantAssumeRole(this.role);
grant?.applyBefore(this.codePipeline);
return actionRole;
}

Expand Down
7 changes: 7 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/lazy-role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ export class LazyRole extends cdk.Resource implements IRole {
return this.instantiate().grantPassRole(identity);
}

/**
* Grant permissions to the given principal to assume this role.
*/
public grantAssumeRole(identity: IPrincipal): Grant {
return this.instantiate().grantAssumeRole(identity);
}

private instantiate(): Role {
if (!this.role) {
const role = new Role(this, 'Default', this.props);
Expand Down
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/principals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,21 @@ export interface ServicePrincipalOpts {
* An IAM principal that represents an AWS service (i.e. sqs.amazonaws.com).
*/
export class ServicePrincipal extends PrincipalBase {
/**
* Translate the given service principal name based on the region it's used in.
*
* For example, for Chinese regions this may (depending on whether that's necessary
* for the given service principal) append `.cn` to the name.
*
* The `region-info` module is used to obtain this information.
*
* @example
* const principalName = iam.ServicePrincipal.servicePrincipalName('ec2.amazonaws.com');
*/
public static servicePrincipalName(service: string): string {
return new ServicePrincipalToken(service, {}).toString();
}

/**
*
* @param service AWS service (i.e. sqs.amazonaws.com)
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/private/immutable-role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,8 @@ export class ImmutableRole extends Resource implements IRole {
public grantPassRole(grantee: IPrincipal): Grant {
return this.role.grantPassRole(grantee);
}

public grantAssumeRole(identity: IPrincipal): Grant {
return this.role.grantAssumeRole(identity);
}
}
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-iam/lib/role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,13 @@ export class Role extends Resource implements IRole {
return this.grant(identity, 'iam:PassRole');
}

/**
* Grant permissions to the given principal to pass this role.
*/
public grantAssumeRole(identity: IPrincipal): Grant {
return this.grant(identity, 'sts:AssumeRole');
}

/**
* Grant the actions defined in actions to the identity Principal on this resource.
*/
Expand Down Expand Up @@ -470,6 +477,14 @@ export class Role extends Resource implements IRole {
return this.grant(identity, 'iam:PassRole');
}

/**
* Grant permissions to the given principal to assume this role.
*/
public grantAssumeRole(identity: IPrincipal) {
return this.grant(identity, 'sts:AssumeRole');
}


/**
* Return a copy of this Role object whose Policies will not be updated
*
Expand Down Expand Up @@ -574,6 +589,11 @@ export interface IRole extends IIdentity {
* Grant permissions to the given principal to pass this role.
*/
grantPassRole(grantee: IPrincipal): Grant;

/**
* Grant permissions to the given principal to assume this role.
*/
grantAssumeRole(grantee: IPrincipal): Grant;
}

function createAssumeRolePolicy(principal: IPrincipal, externalIds: string[]) {
Expand Down
10 changes: 10 additions & 0 deletions packages/@aws-cdk/aws-iam/test/principals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,16 @@ test('AccountPrincipal can specify an organization', () => {
});
});

test('ServicePrincipalName returns just a string representing the principal', () => {
// GIVEN
const usEastStack = new Stack(undefined, undefined, { env: { region: 'us-east-1' } });
const afSouthStack = new Stack(undefined, undefined, { env: { region: 'af-south-1' } });
const principalName = iam.ServicePrincipal.servicePrincipalName('ssm.amazonaws.com');

expect(usEastStack.resolve(principalName)).toEqual('ssm.amazonaws.com');
expect(afSouthStack.resolve(principalName)).toEqual('ssm.af-south-1.amazonaws.com');
});

test('Passing non-string as accountId parameter in AccountPrincipal constructor should throw error', () => {
expect(() => new iam.AccountPrincipal(1234)).toThrowError('accountId should be of type string');
});
Expand Down
24 changes: 24 additions & 0 deletions packages/@aws-cdk/aws-iam/test/role.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,30 @@ describe('IAM role', () => {
});
});

test('a role can grant AssumeRole permissions', () => {
// GIVEN
const stack = new Stack();
const role = new Role(stack, 'Role', { assumedBy: new ServicePrincipal('henk.amazonaws.com') });
const user = new User(stack, 'User');

// WHEN
role.grantAssumeRole(user);

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [
{
Action: 'sts:AssumeRole',
Effect: 'Allow',
Resource: { 'Fn::GetAtt': ['Role1ABCC5F0', 'Arn'] },
},
],
Version: '2012-10-17',
},
});
});

testDeprecated('can supply externalId', () => {
// GIVEN
const stack = new Stack();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ const integ = new IntegTest(app, 'Destinations', {
testCases: [stack],
});

integ.assert.invokeFunction({
integ.assertions.invokeFunction({
functionName: stack.fn.functionName,
invocationType: InvocationType.EVENT,
payload: JSON.stringify({ status: 'OK' }),
});

const message = integ.assert.awsApiCall('SQS', 'receiveMessage', {
const message = integ.assertions.awsApiCall('SQS', 'receiveMessage', {
QueueUrl: stack.queue.queueUrl,
WaitTimeSeconds: 20,
});
Expand Down
8 changes: 7 additions & 1 deletion packages/@aws-cdk/aws-lambda/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,12 @@ export class Function extends FunctionBase {
}
}

if (props.description && !Token.isUnresolved(props.description)) {
if (props.description.length > 256) {
throw new Error(`Function description can not be longer than 256 characters but has ${props.description.length} characters.`);
}
}

const managedPolicies = new Array<iam.IManagedPolicy>();

// the arn is in the form of - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Expand Down Expand Up @@ -1115,7 +1121,7 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett
for (const subnetId of subnetIds) {
if (publicSubnetIds.has(subnetId) && !allowPublicSubnet) {
throw new Error('Lambda Functions in a public subnet can NOT access the internet. ' +
'If you are aware of this limitation and would still like to place the function int a public subnet, set `allowPublicSubnet` to true');
'If you are aware of this limitation and would still like to place the function in a public subnet, set `allowPublicSubnet` to true');
}
}

Expand Down
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2648,6 +2648,31 @@ describe('function', () => {
}).not.toThrow();
});

test('Error when function description is longer than 256 chars', () => {
const stack = new cdk.Stack();
expect(() => new lambda.Function(stack, 'MyFunction', {
code: lambda.Code.fromInline('foo'),
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
description: 'a'.repeat(257),
})).toThrow(/Function description can not be longer than 256 characters/);
});

test('No error when function name is Tokenized and Unresolved', () => {
const stack = new cdk.Stack();
expect(() => {
const realFunctionDescription = 'a'.repeat(257);
const tokenizedFunctionDescription = cdk.Token.asString(new cdk.Intrinsic(realFunctionDescription));

new lambda.Function(stack, 'foo', {
code: new lambda.InlineCode('foo'),
handler: 'index.handler',
runtime: lambda.Runtime.NODEJS_14_X,
description: tokenizedFunctionDescription,
});
}).not.toThrow();
});

describe('FunctionUrl', () => {
test('addFunctionUrl creates a function url with default options', () => {
// GIVEN
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-lambda/test/integ.bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ const integ = new IntegTest(app, 'Bundling', {
stackUpdateWorkflow: false,
});

const invoke = integ.assert.invokeFunction({
const invoke = integ.assertions.invokeFunction({
functionName: stack.functionName,
});
invoke.assert(ExpectedResult.objectLike({
invoke.expect(ExpectedResult.objectLike({
Payload: '200',
}));
app.synth();
21 changes: 11 additions & 10 deletions packages/@aws-cdk/aws-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,15 +522,15 @@ by deploying with CDK version `1.126.0` or later **before** switching this value

```ts
const bucket = new s3.Bucket(this, 'MyBucket', {
transferAcceleration: true,
transferAcceleration: true,
});
```

To access the bucket that is enabled for Transfer Acceleration, you must use a special endpoint. The URL can be generated using method `transferAccelerationUrlForObject`:

```ts
const bucket = new s3.Bucket(this, 'MyBucket', {
transferAcceleration: true,
transferAcceleration: true,
});
bucket.transferAccelerationUrlForObject('objectname');
```
Expand All @@ -540,14 +540,14 @@ bucket.transferAccelerationUrlForObject('objectname');
[Intelligent Tiering](https://docs.aws.amazon.com/AmazonS3/latest/userguide/intelligent-tiering.html) can be configured to automatically move files to glacier:

```ts
new s3.Bucket(this, 'MyBucket', {
intelligentTieringConfigurations: [{
name: 'foo',
prefix: 'folder/name',
archiveAccessTierTime: cdk.Duration.days(90),
deepArchiveAccessTierTime: cdk.Duration.days(180),
tags: [{key: 'tagname', value: 'tagvalue'}]
}],
new s3.Bucket(this, 'MyBucket', {
intelligentTieringConfigurations: [{
name: 'foo',
prefix: 'folder/name',
archiveAccessTierTime: cdk.Duration.days(90),
deepArchiveAccessTierTime: cdk.Duration.days(180),
tags: [{key: 'tagname', value: 'tagvalue'}]
}],
});

```
Expand Down Expand Up @@ -576,6 +576,7 @@ const bucket = new s3.Bucket(this, 'MyBucket', {
// the properties below are optional
noncurrentVersionsToRetain: 123,
}],
objectSizeGreaterThan: 500,
prefix: 'prefix',
transitions: [{
storageClass: s3.StorageClass.GLACIER,
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-s3/lib/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,7 @@ export class Bucket extends BucketBase {
})),
expiredObjectDeleteMarker: rule.expiredObjectDeleteMarker,
tagFilters: self.parseTagFilters(rule.tagFilters),
objectSizeGreaterThan: rule.objectSizeGreaterThan,
};

return x;
Expand Down
Loading

0 comments on commit 2ec115b

Please sign in to comment.