-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add S3_AccessControl hook #238
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# macOS | ||
.DS_Store | ||
._* | ||
|
||
# Maven outputs | ||
.classpath | ||
|
||
# IntelliJ | ||
*.iml | ||
.idea | ||
out.java | ||
out/ | ||
.settings | ||
.project | ||
|
||
# auto-generated files | ||
target/ | ||
|
||
# our logs | ||
rpdk.log* | ||
|
||
# contains credentials | ||
sam-tests/ | ||
|
||
# tests-related | ||
.hypothesis/ | ||
|
||
# generated archive | ||
*.zip |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"artifact_type": "HOOK", | ||
"typeName": "AwsCommunity::S3::AccessControl", | ||
"language": "java", | ||
"runtime": "java8", | ||
"entrypoint": "com.awscommunity.s3.accesscontrol.HookHandlerWrapper::handleRequest", | ||
"testEntrypoint": "com.awscommunity.s3.accesscontrol.HookHandlerWrapper::testEntrypoint", | ||
"settings": { | ||
"version": false, | ||
"subparser_name": null, | ||
"verbose": 0, | ||
"force": false, | ||
"type_name": null, | ||
"artifact_type": null, | ||
"endpoint_url": null, | ||
"region": null, | ||
"target_schemas": [], | ||
"profile": null, | ||
"namespace": [ | ||
"com", | ||
"awscommunity", | ||
"s3", | ||
"accesscontrol" | ||
], | ||
"codegen_template_path": "guided_aws", | ||
"protocolVersion": "2.0.0" | ||
}, | ||
"executableEntrypoint": "com.awscommunity.s3.accesscontrol.HookHandlerWrapperExecutable" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# AwsCommunity::S3::AccessControl | ||
|
||
|
||
- [Overview](#Overview) | ||
- [Usage](#Usage) | ||
- [Example templates](#example-templates) | ||
- [Tests](#Tests) | ||
- [Unit tests](#Unit-tests) | ||
- [Contract tests](#Contract-tests) | ||
- [Hook development notes](#Hook-development-notes) | ||
|
||
|
||
## Overview | ||
This hook for [AWS CloudFormation](https://aws.amazon.com/cloudformation/) validates that the legacy `AccessControl` [property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-accesscontrol) for an `AWS::S3::Bucket` [resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html) is either set to `Private`, or is not present. | ||
|
||
|
||
## Usage | ||
This hook is written in [Kotlin](https://kotlinlang.org/). To build it on your machine, install [Apache Maven](https://maven.apache.org/install.html), and a JDK (8, or 11). For more information, see [Prerequisites for developing hooks](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-walkthrough-java.html#prerequisites-developing-hooks-java). | ||
|
||
Next, you'll need to install the [CloudFormation CLI](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/what-is-cloudformation-cli.html), that you'll use to run contract tests for this hook, and to [submit](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-cli-submit.html) this hook to the CloudFormation registry, as a private extension, in the AWS account and Region(s) of your choice. | ||
|
||
The following example shows how to build and submit the hook to the registry, in the `us-east-1` region for the account you use: | ||
|
||
```shell | ||
cfn generate && mvn clean verify && cfn submit --set-default --region us-east-1 | ||
``` | ||
|
||
After you submit the hook to the registry, you'll need to configure it. One of the way of doing this is to first create a `type_config.json` file as shown next (for more information on `Properties` defined for this hook, see [Configuration options](#Configuration-options)): | ||
|
||
```shell | ||
cat <<EOF > type_config.json | ||
{ | ||
"CloudFormationConfiguration": { | ||
"HookConfiguration": { | ||
"TargetStacks": "ALL", | ||
"FailureMode": "FAIL", | ||
"Properties": { | ||
} | ||
} | ||
} | ||
} | ||
EOF | ||
``` | ||
|
||
and then submit the hook configuration using the [AWS Command Line Interface (AWS CLI)](https://aws.amazon.com/cli/). First, get the [Amazon Resource Name](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) (ARN) for this hook, as follows (examples are for the `us-east-1` region): | ||
|
||
```shell | ||
aws cloudformation list-types \ | ||
--type HOOK \ | ||
--filters TypeNamePrefix=AwsCommunity::S3::AccessControl \ | ||
--query 'TypeSummaries[?TypeName==`AwsCommunity::S3::AccessControl`].TypeArn' \ | ||
--output text \ | ||
--region us-east-1 | ||
``` | ||
|
||
Next, find the ARN value string in the output of the command above, and use it with this command by replacing the placeholder text below in upper case characters for `YOUR_HOOK_ARN`: | ||
|
||
```shell | ||
aws cloudformation set-type-configuration \ | ||
--configuration file://type_config.json \ | ||
--type-arn 'YOUR_HOOK_ARN' \ | ||
--region us-east-1 | ||
``` | ||
|
||
|
||
# Example templates | ||
|
||
Templates in this section are marked as: | ||
- _Non-compliant_: this hook will find the given template to be non-compliant, and | ||
- _Compliant_: the template will be found to be compliant, and should deploy successfully. | ||
|
||
Note that you'll also find templates called `integ-succeed.yml` and `integ-fail.yml` in the `test` directory, that can be used to create stacks for integration testing. | ||
|
||
Non-compliant: the `AccessControl` [property](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html#cfn-s3-bucket-accesscontrol) for the `AWS::S3::Bucket` [resource](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html) is present in the template, and with a value other than `Private`: | ||
|
||
```yaml | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
|
||
Description: Test-only template that describes an Amazon S3 bucket for integration tests. | ||
|
||
Resources: | ||
S3Bucket: | ||
Type: AWS::S3::Bucket | ||
Properties: | ||
AccessControl: PublicRead | ||
``` | ||
|
||
Compliant, example 1: `AccessControl` is present in the template, and with a value of `Private`: | ||
|
||
```yaml | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
|
||
Description: Test-only template that describes an Amazon S3 bucket for integration tests. | ||
|
||
Resources: | ||
S3Bucket: | ||
Type: AWS::S3::Bucket | ||
Properties: | ||
AccessControl: Private | ||
``` | ||
|
||
Compliant, example 2: `AccessControl` is not present in the template: | ||
|
||
```yaml | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
|
||
Description: Test-only template that describes an Amazon S3 bucket for integration tests. | ||
|
||
Resources: | ||
S3Bucket: | ||
Type: AWS::S3::Bucket | ||
``` | ||
|
||
## Tests | ||
|
||
|
||
### Unit tests | ||
Run unit tests, and verify code coverage with: | ||
|
||
```shell | ||
mvn clean verify | ||
``` | ||
|
||
|
||
### Contract tests | ||
Contract tests help you validate hooks you develop work as expected, and are required to pass when you submit a CloudFormation extension such as a hook to the public registry. It is recommended to strive to pass contract tests also when you write a private extension, to help discover potential issues. | ||
|
||
To run contract tests, open a new terminal window and run, from the root directory of this project: | ||
|
||
```shell | ||
sam local start-lambda | ||
``` | ||
|
||
For more information, see [Testing resource types locally using AWS SAM](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-test.html#resource-type-develop-test). | ||
|
||
Open a another terminal window, build this hook, and run contract tests: | ||
|
||
```shell | ||
cfn generate && mvn clean verify && cfn test -v --enforce-timeout 90 | ||
``` | ||
|
||
## Hook development notes | ||
The RPDK will automatically generate the correct hook input model from the schema whenever the project is built via Maven. You can also do this manually with the following command: `cfn generate`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think "RPDK" is a public term. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see it described here. That initial line is actually created by the cfn-cli tool in the README file when you create a new extension project. I have added lines below for this specific Kotlin project, and left the original line intact. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will update this "Hook development notes" section. |
||
|
||
> Please don't modify files under `target/generated-sources/rpdk`, as they will be automatically overwritten. | ||
|
||
The generated code uses [Lombok](https://projectlombok.org/) to annotate Java classes, including classes in the `target/generated-sources/rpdk` path mentioned above. This hook -that is written in Kotlin- needs to consume such Lombok-annotated Java classes: one way to do this is to use [Delombok](https://projectlombok.org/features/delombok) to delombok relevant source files. The `pom.xml` file, for this `AwsCommunity::S3::AccessControl` hook, uses the `delombok` goal for the [lombok.maven plugin](https://github.com/awhitford/lombok.maven) to delombok, during the `process-sources` phase, the `target/generated-sources/rpdk` generated classes into the `target/generated-sources/delombok` target directory that, in turn, is then added as a source with the `add-source` goal for the `build-helper-maven-plugin`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"typeName": "AwsCommunity::S3::AccessControl", | ||
"description": "This hook for AWS CloudFormation validates that the legacy AccessControl property for an AWS::S3::Bucket resource is either set to Private, or is not present.", | ||
"sourceUrl": "https://github.com/aws-cloudformation/community-registry-extensions/tree/main/hooks/S3_AccessControl", | ||
"documentationUrl": "https://github.com/aws-cloudformation/community-registry-extensions/blob/main/hooks/S3_AccessControl/README.md", | ||
"typeConfiguration": { | ||
"properties": { | ||
}, | ||
"additionalProperties": false | ||
}, | ||
"required": [], | ||
"handlers": { | ||
"preCreate": { | ||
"targetNames": [ | ||
"AWS::S3::Bucket" | ||
], | ||
"permissions": [] | ||
}, | ||
"preUpdate": { | ||
"targetNames": [ | ||
"AWS::S3::Bucket" | ||
], | ||
"permissions": [] | ||
} | ||
}, | ||
"additionalProperties": false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# AwsCommunity::S3::AccessControl | ||
|
||
## Activation | ||
|
||
To activate a hook in your account, use the following JSON as the `Configuration` request parameter for [`SetTypeConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_SetTypeConfiguration.html) API request. | ||
|
||
### Configuration | ||
|
||
<pre> | ||
{ | ||
"CloudFormationConfiguration": { | ||
"<a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-hook-configuration" title="HookConfiguration">HookConfiguration</a>": { | ||
"<a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-targetstacks" title="TargetStacks">TargetStacks</a>": <a href="#footnote-1">"ALL" | "NONE"</a>, | ||
"<a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-failuremode" title="FailureMode">FailureMode</a>": <a href="#footnote-1">"FAIL" | "WARN"</a> , | ||
"<a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-properties" title="Properties">Properties</a>" : { | ||
} | ||
} | ||
} | ||
} | ||
</pre> | ||
|
||
--- | ||
|
||
## Targets | ||
|
||
* `AWS::S3::Bucket` | ||
|
||
--- | ||
|
||
<p id="footnote-1"><i> Please note that the enum values for <a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-targetstacks" title="TargetStacks"> | ||
TargetStacks</a> and <a href="https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/hooks-structure.html#hooks-failuremode" title="FailureMode">FailureMode</a> | ||
might go out of date, please refer to their official documentation page for up-to-date values. </i></p> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
Description: > | ||
This CloudFormation template creates a role assumed by CloudFormation | ||
during Hook operations on behalf of the customer. | ||
|
||
Resources: | ||
ExecutionRole: | ||
Type: AWS::IAM::Role | ||
Properties: | ||
MaxSessionDuration: 8400 | ||
AssumeRolePolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Allow | ||
Principal: | ||
Service: | ||
- hooks.cloudformation.amazonaws.com | ||
- resources.cloudformation.amazonaws.com | ||
Action: sts:AssumeRole | ||
Condition: | ||
StringEquals: | ||
aws:SourceAccount: | ||
Ref: AWS::AccountId | ||
StringLike: | ||
aws:SourceArn: | ||
Fn::Sub: arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:type/hook/AwsCommunity-S3-AccessControl/* | ||
Path: "/" | ||
Policies: | ||
- PolicyName: HookTypePolicy | ||
PolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Deny | ||
Action: | ||
- "*" | ||
Resource: "*" | ||
Outputs: | ||
ExecutionRoleArn: | ||
Value: | ||
Fn::GetAtt: ExecutionRole.Arn |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
AWSTemplateFormatVersion: "2010-09-09" | ||
Description: > | ||
This CloudFormation template creates a role assumed by CloudFormation | ||
during Hook operations on behalf of the customer. | ||
|
||
Resources: | ||
ExecutionRole: | ||
Type: AWS::IAM::Role | ||
Properties: | ||
MaxSessionDuration: 8400 | ||
AssumeRolePolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Allow | ||
Principal: | ||
Service: | ||
- hooks.cloudformation.amazonaws.com | ||
- resources.cloudformation.amazonaws.com | ||
Action: sts:AssumeRole | ||
Condition: | ||
StringEquals: | ||
aws:SourceAccount: | ||
Ref: AWS::AccountId | ||
StringLike: | ||
aws:SourceArn: | ||
Fn::Sub: arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:type/hook/AwsCommunity-S3-AccessControl/* | ||
Path: "/" | ||
Policies: | ||
- PolicyName: HookTypePolicy | ||
PolicyDocument: | ||
Version: '2012-10-17' | ||
Statement: | ||
- Effect: Deny | ||
Action: | ||
- "*" | ||
Resource: "*" | ||
Outputs: | ||
ExecutionRoleArn: | ||
Value: | ||
Fn::GetAtt: ExecutionRole.Arn |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"AWS::S3::Bucket": { | ||
"resourceProperties": { | ||
"AccessControl": "PublicRead" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"AWS::S3::Bucket": { | ||
"resourceProperties": {} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"AWS::S3::Bucket": { | ||
"resourceProperties": { | ||
"AccessControl": "Private" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
lombok.addLombokGeneratedAnnotation = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace double spaces after periods with single space. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do - thank you!