Skip to content

Commit

Permalink
Merge branch 'master' into njlynch/edge-function-ssm-name
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Oct 7, 2021
2 parents 05b8881 + 5436ce2 commit 282d26a
Show file tree
Hide file tree
Showing 16 changed files with 355 additions and 160 deletions.
200 changes: 132 additions & 68 deletions packages/@aws-cdk/aws-apigateway/README.md

Large diffs are not rendered by default.

20 changes: 11 additions & 9 deletions packages/@aws-cdk/aws-apigateway/lib/access-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,15 +486,17 @@ export class AccessLogFormat {
* Custom log format.
* You can create any log format string. You can easily get the $ context variable by using the methods of AccessLogField.
* @param format
* @example custom(JSON.stringify({
* requestId: AccessLogField.contextRequestId(),
* sourceIp: AccessLogField.contextIdentitySourceIp(),
* method: AccessLogFiled.contextHttpMethod(),
* userContext: {
* sub: AccessLogField.contextAuthorizerClaims('sub'),
* email: AccessLogField.contextAuthorizerClaims('email')
* }
* }))
* @example
*
* apigateway.AccessLogFormat.custom(JSON.stringify({
* requestId: apigateway.AccessLogField.contextRequestId(),
* sourceIp: apigateway.AccessLogField.contextIdentitySourceIp(),
* method: apigateway.AccessLogField.contextHttpMethod(),
* userContext: {
* sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'),
* email: apigateway.AccessLogField.contextAuthorizerClaims('email')
* }
* }))
*/
public static custom(format: string): AccessLogFormat {
return new AccessLogFormat(format);
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-apigateway/lib/api-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export abstract class ApiDefinition {
* schema of OpenAPI 2.0 or OpenAPI 3.0
*
* @example
* ApiDefinition.fromInline({
*
* apigateway.ApiDefinition.fromInline({
* openapi: '3.0.2',
* paths: {
* '/pets': {
Expand Down
5 changes: 3 additions & 2 deletions packages/@aws-cdk/aws-apigateway/lib/integrations/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ export interface LambdaIntegrationOptions extends IntegrationOptions {
*
* @example
*
* const handler = new lambda.Function(this, 'MyFunction', ...);
* api.addMethod('GET', new LambdaIntegration(handler));
* declare const resource: apigateway.Resource;
* declare const handler: lambda.Function;
* resource.addMethod('GET', new apigateway.LambdaIntegration(handler));
*
*/
export class LambdaIntegration extends AwsIntegration {
Expand Down
9 changes: 6 additions & 3 deletions packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,18 @@ export interface MethodOptions {
*
* @example
*
* declare const api: apigateway.RestApi;
* declare const userLambda: lambda.Function;
*
* const userModel: apigateway.Model = api.addModel('UserModel', {
* schema: {
* type: apigateway.JsonSchemaType.OBJECT
* type: apigateway.JsonSchemaType.OBJECT,
* properties: {
* userId: {
* type: apigateway.JsonSchema.STRING
* type: apigateway.JsonSchemaType.STRING
* },
* name: {
* type: apigateway.JsonSchema.STRING
* type: apigateway.JsonSchemaType.STRING
* }
* },
* required: ['userId']
Expand Down
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-apigateway/rosetta/default.ts-fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Fixture with packages imported, but nothing else
import { Construct, Stack } from '@aws-cdk/core';
import apigateway = require('@aws-cdk/aws-apigateway');
import cognito = require('@aws-cdk/aws-cognito');
import lambda = require('@aws-cdk/aws-lambda');
import iam = require('@aws-cdk/aws-iam');
import s3 = require('@aws-cdk/aws-s3');
import ec2 = require('@aws-cdk/aws-ec2');
import logs = require('@aws-cdk/aws-logs');

class Fixture extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);

/// here
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RootStack extends Stack {
});
new DeployStack(this, {
restApiId: restApi.restApiId,
methods: [...petsStack.methods, ...booksStack.methods],
methods: petsStack.methods.concat(booksStack.methods),
});

new CfnOutput(this, 'PetsURL', {
Expand Down Expand Up @@ -117,7 +117,11 @@ class DeployStack extends NestedStack {
const deployment = new Deployment(this, 'Deployment', {
api: RestApi.fromRestApiId(this, 'RestApi', props.restApiId),
});
(props.methods ?? []).forEach((method) => deployment.node.addDependency(method));
if (props.methods) {
for (const method of props.methods) {
deployment.node.addDependency(method);
}
}
new Stage(this, 'Stage', { deployment });
}
}
Expand Down
20 changes: 15 additions & 5 deletions packages/@aws-cdk/aws-iam/lib/policy-statement.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as cdk from '@aws-cdk/core';
import { AnyPrincipal } from '.';
import { Group } from './group';
import {
AccountPrincipal, AccountRootPrincipal, Anyone, ArnPrincipal, CanonicalUserPrincipal,
AccountPrincipal, AccountRootPrincipal, ArnPrincipal, CanonicalUserPrincipal,
FederatedPrincipal, IPrincipal, PrincipalBase, PrincipalPolicyFragment, ServicePrincipal, ServicePrincipalOpts,
} from './principals';
import { mergePrincipal } from './util';
import { LITERAL_STRING_KEY, mergePrincipal } from './util';

const ensureArrayOrUndefined = (field: any) => {
if (field === undefined) {
Expand Down Expand Up @@ -239,7 +240,7 @@ export class PolicyStatement {
* Adds all identities in all accounts ("*") to this policy statement
*/
public addAnyPrincipal() {
this.addPrincipals(new Anyone());
this.addPrincipals(new AnyPrincipal());
}

//
Expand Down Expand Up @@ -370,6 +371,11 @@ export class PolicyStatement {
function _normPrincipal(principal: { [key: string]: any[] }) {
const keys = Object.keys(principal);
if (keys.length === 0) { return undefined; }

if (LITERAL_STRING_KEY in principal) {
return principal[LITERAL_STRING_KEY][0];
}

const result: any = {};
for (const key of keys) {
const normVal = _norm(principal[key]);
Expand Down Expand Up @@ -600,9 +606,13 @@ class JsonPrincipal extends PrincipalBase {
constructor(json: any = { }) {
super();

// special case: if principal is a string, turn it into an "AWS" principal
// special case: if principal is a string, turn it into a "LiteralString" principal,
// so we render the exact same string back out.
if (typeof(json) === 'string') {
json = { AWS: json };
json = { [LITERAL_STRING_KEY]: [json] };
}
if (typeof(json) !== 'object') {
throw new Error(`JSON IAM principal should be an object, got ${JSON.stringify(json)}`);
}

this.policyFragment = {
Expand Down
40 changes: 38 additions & 2 deletions packages/@aws-cdk/aws-iam/lib/principals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Default, RegionInfo } from '@aws-cdk/region-info';
import { IOpenIdConnectProvider } from './oidc-provider';
import { Condition, Conditions, PolicyStatement } from './policy-statement';
import { ISamlProvider } from './saml-provider';
import { mergePrincipal } from './util';
import { LITERAL_STRING_KEY, mergePrincipal } from './util';

/**
* Any object that has an associated principal that a permission can be granted to
Expand Down Expand Up @@ -252,6 +252,15 @@ export class PrincipalWithConditions implements IPrincipal {
*
* This consists of the JSON used in the "Principal" field, and optionally a
* set of "Condition"s that need to be applied to the policy.
*
* Generally, a principal looks like:
*
* { '<TYPE>': ['ID', 'ID', ...] }
*
* And this is also the type of the field `principalJson`. However, there is a
* special type of principal that is just the string '*', which is treated
* differently by some services. To represent that principal, `principalJson`
* should contain `{ 'LiteralString': ['*'] }`.
*/
export class PrincipalPolicyFragment {
/**
Expand Down Expand Up @@ -545,7 +554,14 @@ export class AccountRootPrincipal extends AccountPrincipal {
}

/**
* A principal representing all identities in all accounts
* A principal representing all AWS identities in all accounts
*
* Some services behave differently when you specify `Principal: '*'`
* or `Principal: { AWS: "*" }` in their resource policy.
*
* `AnyPrincipal` renders to `Principal: { AWS: "*" }`. This is correct
* most of the time, but in cases where you need the other principal,
* use `StarPrincipal` instead.
*/
export class AnyPrincipal extends ArnPrincipal {
constructor() {
Expand All @@ -563,6 +579,26 @@ export class AnyPrincipal extends ArnPrincipal {
*/
export class Anyone extends AnyPrincipal { }

/**
* A principal that uses a literal '*' in the IAM JSON language
*
* Some services behave differently when you specify `Principal: "*"`
* or `Principal: { AWS: "*" }` in their resource policy.
*
* `StarPrincipal` renders to `Principal: *`. Most of the time, you
* should use `AnyPrincipal` instead.
*/
export class StarPrincipal extends PrincipalBase {
public readonly policyFragment: PrincipalPolicyFragment = {
principalJson: { [LITERAL_STRING_KEY]: ['*'] },
conditions: {},
};

public toString() {
return 'StarPrincipal()';
}
}

/**
* Represents a principal that has multiple types of principals. A composite principal cannot
* have conditions. i.e. multiple ServicePrincipals that form a composite principal
Expand Down
16 changes: 15 additions & 1 deletion packages/@aws-cdk/aws-iam/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { IPolicy } from './policy';

const MAX_POLICY_NAME_LEN = 128;

export const LITERAL_STRING_KEY = 'LiteralString';

export function undefinedIfEmpty(f: () => string[]): string[] {
return Lazy.list({
produce: () => {
Expand Down Expand Up @@ -67,10 +69,18 @@ export class AttachedPolicies {

/**
* Merge two dictionaries that represent IAM principals
*
* Does an in-place merge.
*/
export function mergePrincipal(target: { [key: string]: string[] }, source: { [key: string]: string[] }) {
// If one represents a literal string, the other one must be empty
if ((LITERAL_STRING_KEY in source && !isEmptyObject(target)) ||
(LITERAL_STRING_KEY in target && !isEmptyObject(source))) {
throw new Error(`Cannot merge principals ${JSON.stringify(target)} and ${JSON.stringify(source)}; if one uses a literal principal string the other one must be empty`);
}

for (const key of Object.keys(source)) {
target[key] = target[key] || [];
target[key] = target[key] ?? [];

let value = source[key];
if (!Array.isArray(value)) {
Expand Down Expand Up @@ -123,4 +133,8 @@ export class UniqueStringSet implements IResolvable, IPostProcessor {
public toString(): string {
return Token.asString(this);
}
}

function isEmptyObject(x: { [key: string]: any }): boolean {
return Object.keys(x).length === 0;
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-iam/test/policy-document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ describe('IAM policy document', () => {
});
}).toThrow(/Statement must be an array/);
});

});

test('adding another condition with the same operator does not delete the original', () => {
Expand Down
25 changes: 25 additions & 0 deletions packages/@aws-cdk/aws-iam/test/policy-statement.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,32 @@ describe('IAM policy statement', () => {
const doc2 = PolicyDocument.fromJson(doc1.toJSON());

expect(stack.resolve(doc2)).toEqual(stack.resolve(doc1));
});

test('should not convert `Principal: *` to `Principal: { AWS: * }`', () => {
const stack = new Stack();
const s = PolicyStatement.fromJson({
Action: ['service:action1'],
Principal: '*',
Resource: '*',
});

const doc1 = new PolicyDocument();
doc1.addStatements(s);

const rendered = stack.resolve(doc1);

expect(rendered).toEqual({
Statement: [
{
Action: 'service:action1',
Effect: 'Allow',
Principal: '*',
Resource: '*',
},
],
Version: '2012-10-17',
});
});

test('parses a given notPrincipal', () => {
Expand Down
29 changes: 29 additions & 0 deletions packages/@aws-cdk/aws-iam/test/principals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,35 @@ test('SAML principal', () => {
});
});

test('StarPrincipal', () => {
// GIVEN
const stack = new Stack();

// WHEN
const pol = new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: ['service:action'],
resources: ['*'],
principals: [new iam.StarPrincipal()],
}),
],
});

// THEN
expect(stack.resolve(pol)).toEqual({
Statement: [
{
Action: 'service:action',
Effect: 'Allow',
Principal: '*',
Resource: '*',
},
],
Version: '2012-10-17',
});
});

test('PrincipalWithConditions.addCondition should work', () => {
// GIVEN
const stack = new Stack();
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-msk/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ export class Cluster extends ClusterBase {
new iam.PolicyStatement({
sid:
'Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS Secrets Manager',
principals: [new iam.Anyone()],
principals: [new iam.AnyPrincipal()],
actions: [
'kms:Encrypt',
'kms:Decrypt',
Expand Down
Loading

0 comments on commit 282d26a

Please sign in to comment.