Skip to content
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

First commit after repackage and removal of build/ which included AWS… #40

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# contains credentials
sam-tests/

rpdk.log*

.DS_Store
21 changes: 21 additions & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/.rpdk-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"artifact_type": "HOOK",
"typeName": "AWSSamples::Ec2SsmSmOnly::Hook",
"language": "python36",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be python37 at least.

"runtime": "python3.6",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be python3.7 at least.

"entrypoint": "awssamples_ec2ssmsmonly_hook.handlers.hook",
"testEntrypoint": "awssamples_ec2ssmsmonly_hook.handlers.test_entrypoint",
"settings": {
"version": false,
"subparser_name": null,
"verbose": 0,
"force": false,
"type_name": null,
"artifact_type": null,
"endpoint_url": null,
"region": null,
"target_schemas": [],
"use_docker": true,
"protocolVersion": "2.0.0"
}
}
80 changes: 80 additions & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# AWSSamples::Ec2SsmSmOnly::Hook

This AWS CloudFormation Hook validates that an EC2 instance to be deployed, can only be accessed using [AWS Systems Manager Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html).

The Hook currently checks [AWS::EC2::Instance](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html) and [AWS::EC2::LaunchTemplate](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-launchtemplate.html) resource types. Instances deploed via [AWS::AutoScaling::LaunchConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-launchconfiguration.html) are not currently checked.

### Validation Overview ###
The validation consists of the following high-level steps:
1. Ensure the instance has a [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) assigned
2. Simulate the [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) role to ensure it 'Allows' the following permissions:
* `ssmmessages:CreateControlChannel`
* `ssmmessages:CreateDataChannel`
* `ssmmessages:OpenControlChannel`
* `ssmmessages:OpenDataChannel`

3. Verify none of the instance security groups allow ingress on 22/SSH if a Linux instance or 3389/RDP if a Windows instance.

Security Groups are checked depending on how specified for the instance:
* `SecurityGroupIds` property (non-default VPC)
* `SecurityGroups` property (EC2-Classic, default VPC)
* `NetworkInterfaces` property

### Requiring KMS Encrypted SSM Sessions
The hook can enforce KMS key encryption of SSM Session data by requiring the instance [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) role to include the `kms:decrypt` permission. You can control this by setting the `requireSessionManagerEncryption` property in the Hook Configuration JSON as shown below.

<pre>
{
"CloudFormationConfiguration": {
"HookConfiguration": {
"TargetStacks": "ALL",
"FailureMode": "FAIL",
"Properties": {
<b>"requireSessionManagerEncryption": true</b>
}
}
}
}
</pre>
See [Defining the account-level configuration of an extension](https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-model.html#resource-type-howto-configuration) in the *CloudFormation CLI User Guide*.

### Testing

An AWS CloudFormation template is provided in the `testing` folder to exercise various failure use-cases by manipulating the provided template parameters:

* `IncludeInstanceProfile: (True|False)`

Set to `False` to remove the [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) property which should result in an `IamInstanceProfile property missing or empty value` error

* `ManagedOrManualIAMPolicy (Managed|Manual)`

Set to `Managed` to generate the [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) role policy using the `arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore` IAM Managed policy.

Set to `Manual` to generate the [IamInstanceProfile](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#cfn-ec2-instance-iaminstanceprofile) role policy using an inline policy containing the required SSM Session Manager permissions
* `TestIllegalManualSSMPolicies (True|False)`

Set to `True` to omit the `ssmmessages:OpenControlChannel` permission from the policy which should result in an `ssmmessages:OpenControlChannel: Implicit Deny` error

* `IncludeExplicitSecurityGroup (True|False)`

Set to `True` to include a Security Group for the instance that does not reference port 22/SSH

* `IncludeExplicitSSHSecurityGroup (True|False)`

Set to `True` to include a Security Group for the instance that does includes an ingress rule for 22/SSH. This should result in an `Security Group contains an SSH ingress rule` error

* `UseProvidedDefaultVpcValues (True|False)`

Set to `False` to have the template create a custom VPC and Subnet, and deploy the instance into it

Set to `True` to deploy the instance into the *default* VPC and Subnet you provide using the `DefaultVpc` and `DefaultVpcSubnetId` parameters.

* `IncludeSSMKMS (True|False)`

Set to 'True' to have the template generate an KMS key and reference it with the `kms:decrypt` action in the IAMInstanceRole.

If `requireSessionManagerEncryption` property in the Hook Configuration is set to `True` and you set `IncludeSSMKMS` to `False`, you should get a `kms:decrypt: Implicit Deny` error

> **IMPORTANT**

> During a stack update, if a dependant property of the instance is changed, the hook will not be called. This means its possible during a stack update, to bypass the validation checks such as adding an 22/SSH ingress rule to the instances' referenced Security Group.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"properties": {
"requireSessionManagerEncryption": {
"type": "boolean",
"description": "Set to 'true' to require kms:decrypt action with a valid key-name resource",
"enum": [
true,
false
],
"default": false
}
},
"additionalProperties": false,
"definitions": {},
"typeName": "AWSSamples::Ec2SsmSmOnly::Hook"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"typeName": "AWSSamples::Ec2SsmSmOnly::Hook",
"description": "Checks that EC2 instances being deployed are configured to only allow use of SSM Session Manager to access the instance",
"sourceUrl": "https://github.com/aws-cloudformation/example-sse-hook",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the URL accordingly.

"documentationUrl": "https://github.com/aws-cloudformation/example-sse-hook/blob/master/README.md",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the URL accordingly.

"typeConfiguration": {
"properties": {
"requireSessionManagerEncryption": {
"type": "boolean",
"description": "Set to 'true' to require kms:decrypt action with a valid key-name resource",
"enum": [
true,
false
],
"default": false
}
},
"additionalProperties": false
},
"required": [],
"handlers": {
"preCreate": {
"targetNames": [
"AWS::EC2::Instance",
"AWS::EC2::LaunchTemplate"
],
"permissions": [
"ec2:DescribeSecurityGroups",
"ec2:DescribeImages",
"iam:GetInstanceProfile",
"iam:SimulatePrincipalPolicy",
"iam:GetRole"
]
},
"preUpdate": {
"targetNames": [
"AWS::EC2::Instance",
"AWS::EC2::LaunchTemplate"
],
"permissions": [
"ec2:DescribeSecurityGroups",
"ec2:DescribeImages",
"iam:GetInstanceProfile",
"iam:SimulatePrincipalPolicy",
"iam:GetRole"
]
}
},
"additionalProperties": false
}
44 changes: 44 additions & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/hook-role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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/AWSSamples-Ec2SsmSmOnly-Hook/*
Path: "/"
Policies:
- PolicyName: HookTypePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "ec2:DescribeImages"
- "ec2:DescribeSecurityGroups"
- "iam:GetInstanceProfile"
- "iam:GetRole"
- "iam:SimulatePrincipalPolicy"
Resource: "*"
Outputs:
ExecutionRoleArn:
Value:
Fn::GetAtt: ExecutionRole.Arn
1 change: 1 addition & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cloudformation-cli-python-lib==2.2.hooks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be cloudformation-cli-python-lib>=2.1.9 at least.

32 changes: 32 additions & 0 deletions hooks/python-hooks/ec2-ssm-sm-only/resource-role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
AWSTemplateFormatVersion: "2010-09-09"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file does not seem to be needed - please remove it, or clarify.

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: cfnhooksservice.cloudformation.aws.internal
Action: sts:AssumeRole
Path: "/"
Policies:
- PolicyName: ResourceTypePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- "iam:GetInstanceProfile"
- "iam:SimulatePrincipalPolicy"
Resource: "*"
Outputs:
ExecutionRoleArn:
Value:
Fn::GetAtt: ExecutionRole.Arn
Loading