Skip to content

Commit

Permalink
Merge branch 'main' into ecs-service-add-security-groups
Browse files Browse the repository at this point in the history
  • Loading branch information
hamilton-earthscope authored Sep 14, 2024
2 parents bde83d9 + 386fca3 commit 64377d7
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 12 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"Type": "AWS::ApiGatewayV2::Api",
"Properties": {
"Name": "HttpApi",
"ProtocolType": "HTTP"
"ProtocolType": "HTTP",
"RouteSelectionExpression": "${request.method} ${request.path}"
}
},
"HttpApiDefaultStage3EEB07D6": {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import * as apigw from 'aws-cdk-lib/aws-apigatewayv2';
const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-cdk-aws-apigatewayv2');

new apigw.HttpApi(stack, 'HttpApi');
new apigw.HttpApi(stack, 'HttpApi', {
routeSelectionExpression: true,
});

new IntegTest(app, 'http-api', {
testCases: [stack],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def helm_handler(event, context):

def get_oci_cmd(repository, version):
# Generates OCI command based on pattern. Public ECR vs Private ECR are treated differently.
private_ecr_pattern = 'oci://(?P<registry>\d+\.dkr\.ecr\.(?P<region>[a-z0-9\-]+)\.amazonaws\.com(\.cn)?)*'
private_ecr_pattern = 'oci://(?P<registry>\d+\.dkr\.ecr\.(?P<region>[a-z0-9\-]+)\.(?P<domain>[a-z0-9\.-]+))*'
public_ecr_pattern = 'oci://(?P<registry>public\.ecr\.aws)*'

private_registry = re.match(private_ecr_pattern, repository).groupdict()
Expand Down
8 changes: 8 additions & 0 deletions packages/aws-cdk-lib/aws-apigatewayv2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ new apigwv2.HttpApi(this, 'HttpProxyApi', {
});
```

The `routeSelectionExpression` option allows configuring the HTTP API to accept only `${request.method} ${request.path}`. Setting it to `true` automatically applies this value.

```ts
new apigwv2.HttpApi(this, 'HttpProxyApi', {
routeSelectionExpression: true,
});
```

### Cross Origin Resource Sharing (CORS)

[Cross-origin resource sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a browser security
Expand Down
10 changes: 10 additions & 0 deletions packages/aws-cdk-lib/aws-apigatewayv2/lib/http/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ export interface HttpApiProps {
* @default - no default authorization scopes
*/
readonly defaultAuthorizationScopes?: string[];

/**
* Whether to set the default route selection expression for the API.
*
* When enabled, "${request.method} ${request.path}" is set as the default route selection expression.
*
* @default false
*/
readonly routeSelectionExpression?: boolean;
}

/**
Expand Down Expand Up @@ -434,6 +443,7 @@ export class HttpApi extends HttpApiBase {
corsConfiguration,
description: props?.description,
disableExecuteApiEndpoint: this.disableExecuteApiEndpoint,
routeSelectionExpression: props?.routeSelectionExpression ? '${request.method} ${request.path}' : undefined,
};

const resource = new CfnApi(this, 'Resource', apiProps);
Expand Down
26 changes: 26 additions & 0 deletions packages/aws-cdk-lib/aws-apigatewayv2/test/http/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,32 @@ describe('HttpApi', () => {
});
});

test('routeSelectionExpression is enabled', () => {
const stack = new Stack();
new HttpApi(stack, 'api', {
routeSelectionExpression: true,
});

Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Api', {
Name: 'api',
ProtocolType: 'HTTP',
RouteSelectionExpression: '${request.method} ${request.path}',
});
});

test.each([false, undefined])('routeSelectionExpression is not enabled', (routeSelectionExpression) => {
const stack = new Stack();
new HttpApi(stack, 'api', {
routeSelectionExpression,
});

Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Api', {
Name: 'api',
ProtocolType: 'HTTP',
RouteSelectionExpression: Match.absent(),
});
});

test('can add a vpc links', () => {
// GIVEN
const stack = new Stack();
Expand Down
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ export class InterfaceVpcEndpointAwsService implements IInterfaceVpcEndpointServ
public static readonly REKOGNITION_STREAMING = new InterfaceVpcEndpointAwsService('streaming-rekognition');
public static readonly REKOGNITION_STREAMING_FIPS = new InterfaceVpcEndpointAwsService('streaming-rekognition-fips');
public static readonly REPOST_SPACE = new InterfaceVpcEndpointAwsService('repostspace');
public static readonly RESOURCE_ACCESS_MANAGER = new InterfaceVpcEndpointAwsService('ram');
public static readonly ROBOMAKER = new InterfaceVpcEndpointAwsService('robomaker');
public static readonly RECYCLE_BIN = new InterfaceVpcEndpointAwsService('rbin');
public static readonly S3 = new InterfaceVpcEndpointAwsService('s3');
Expand Down
10 changes: 10 additions & 0 deletions packages/aws-cdk-lib/aws-eks/test/helm-chart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,15 @@ describe('helm chart', () => {
// THEN
Template.fromStack(stack).hasResourceProperties(eks.HelmChart.RESOURCE_TYPE, { SkipCrds: true });
});
test('should use private ecr repo when specified', () => {
// GIVEN
const { stack, cluster } = testFixtureCluster();

// WHEN
new eks.HelmChart(stack, 'MyPrivateChart', { cluster, chart: 'chart', repository: 'oci://012345678.dkr.ecr.us-east-1.amazonaws.com/private-repo' });

// THEN
Template.fromStack(stack).hasResourceProperties(eks.HelmChart.RESOURCE_TYPE, { Repository: 'oci://012345678.dkr.ecr.us-east-1.amazonaws.com/private-repo' });
});
});
});
111 changes: 111 additions & 0 deletions packages/aws-cdk-lib/aws-s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,117 @@ const bucket = new s3.Bucket(this, 'MyBucket', {
});
```

The above code will create a new bucket policy if none exists or update the
existing bucket policy to allow access log delivery.

However, there could be an edge case if the `accessLogsBucket` also defines a bucket
policy resource using the L1 Construct. Although the mixing of L1 and L2 Constructs is not
recommended, there are no mechanisms in place to prevent users from doing this at the moment.

```ts
const bucketName = "my-favorite-bucket-name";
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
bucketName,
});

// Creating a bucket policy using L1
const bucketPolicy = new s3.CfnBucketPolicy(this, "BucketPolicy", {
bucket: bucketName,
policyDocument: {
Statement: [
{
Action: 's3:*',
Effect: 'Deny',
Principal: {
AWS: '*',
},
Resource: [
accessLogsBucket.bucketArn,
`${accessLogsBucket.bucketArn}/*`
],
},
],
Version: '2012-10-17',
},
});

// 'serverAccessLogsBucket' will create a new L2 bucket policy
// to allow log delivery and overwrite the L1 bucket policy.
const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

The above example uses the L2 Bucket Construct with the L1 CfnBucketPolicy Construct. However,
when `serverAccessLogsBucket` is set, a new L2 Bucket Policy resource will be created
which overwrites the permissions defined in the L1 Bucket Policy causing unintended
behaviours.

As noted above, we highly discourage the mixed usage of L1 and L2 Constructs. The recommended
approach would to define the bucket policy using `addToResourcePolicy` method.

```ts
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
});

accessLogsBucket.addToResourcePolicy(
new iam.PolicyStatement({
actions: ['s3:*'],
resources: [accessLogsBucket.bucketArn, accessLogsBucket.arnForObjects('*')],
principals: [new iam.AnyPrincipal()],
})
)

const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

Alternatively, users can use the L2 Bucket Policy Construct
`BucketPolicy.fromCfnBucketPolicy` to wrap around `CfnBucketPolicy` Construct. This will allow the subsequent bucket policy generated by `serverAccessLogsBucket` usage to append to the existing bucket policy instead of overwriting.

```ts
const bucketName = "my-favorite-bucket-name";
const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', {
objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED,
bucketName,
});

const bucketPolicy = new s3.CfnBucketPolicy(this, "BucketPolicy", {
bucket: bucketName,
policyDocument: {
Statement: [
{
Action: 's3:*',
Effect: 'Deny',
Principal: {
AWS: '*',
},
Resource: [
accessLogsBucket.bucketArn,
`${accessLogsBucket.bucketArn}/*`
],
},
],
Version: '2012-10-17',
},
});

// Wrap L1 Construct with L2 Bucket Policy Construct. Subsequent
// generated bucket policy to allow access log delivery would append
// to the current policy.
s3.BucketPolicy.fromCfnBucketPolicy(bucketPolicy);

const bucket = new s3.Bucket(this, 'MyBucket', {
serverAccessLogsBucket: accessLogsBucket,
serverAccessLogsPrefix: 'logs',
});
```

## S3 Inventory

An [inventory](https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html) contains a list of the objects in the source bucket and metadata for each object. The inventory lists are stored in the destination bucket as a CSV file compressed with GZIP, as an Apache optimized row columnar (ORC) file compressed with ZLIB, or as an Apache Parquet (Parquet) file compressed with Snappy.
Expand Down

0 comments on commit 64377d7

Please sign in to comment.