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

feature: Configuration and docs to enable SSM Quick Setup patch policies (centralized patching) #1157

Merged
merged 8 commits into from
Jun 14, 2023
Merged
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
5,594 changes: 5,594 additions & 0 deletions reference-artifacts/SAMPLE_CONFIGS/config.SSM-Patching-example.json

Large diffs are not rendered by default.

103 changes: 103 additions & 0 deletions reference-artifacts/config-rules/src/ssm-patching-role-tags/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const AWS = require('aws-sdk');
AWS.config.logger = console;

const config = new AWS.ConfigService();

const APPLICABLE_RESOURCES = ['AWS::IAM::Role'];

exports.handler = async function (event, context) {
console.log(`Custom Rule for checking Tags on IAM Roles to support SSM Quick Setup Patching...`);
console.log(JSON.stringify(event, null, 2));

const invokingEvent = JSON.parse(event.invokingEvent);
const invocationType = invokingEvent.messageType;
const ruleParams = JSON.parse(event.ruleParameters || '{}');
if (!ruleParams.RoleNames || !ruleParams.QSConfigID) {
throw new Error('Either "RoleNames" or "QSConfigID" are required')
}
if (invocationType === 'ScheduledNotification') {
return;
}

const configurationItem = invokingEvent.configurationItem;

const evaluation = await evaluateCompliance({
configurationItem,
ruleParams,
});

console.debug(`Evaluation`);
console.debug(JSON.stringify(evaluation, null, 2));

await config
.putEvaluations({
ResultToken: event.resultToken,
Evaluations: [
{
ComplianceResourceId: configurationItem.resourceId,
ComplianceResourceType: configurationItem.resourceType,
ComplianceType: evaluation.complianceType,
OrderingTimestamp: configurationItem.configurationItemCaptureTime,
Annotation: evaluation.annotation,
},
],
})
.promise();
};

async function evaluateCompliance(props) {
const { configurationItem, ruleParams } = props;
if (!APPLICABLE_RESOURCES.includes(configurationItem.resourceType)) {
return {
complianceType: 'NOT_APPLICABLE',
annotation: `The rule doesn't apply to resources of type ${configurationItem.resourceType}`,
};
} else if (configurationItem.configurationItemStatus === 'ResourceDeleted') {
return {
complianceType: 'NOT_APPLICABLE',
annotation: 'The configuration item was deleted and could not be validated',
};
} else if (configurationItem.configurationItemStatus === 'ResourceNotRecorded' || configurationItem.configurationItemStatus === 'ResourceDeletedNotRecorded') {
return {
complianceType: 'NOT_APPLICABLE',
annotation: 'The configuration item is not recorded in this region and need not be validated',
};
}

if (configurationItem.configuration) {
const existingTags = configurationItem.configuration.tags;
const requiredQAConfigID = ruleParams.QSConfigID;
const targetRoleNames = ruleParams.RoleNames.split(',').map(item => item.trim());

const tagKey = `QSConfigId-${requiredQAConfigID}`;

if (!targetRoleNames.includes(configurationItem.configuration.roleName)) {
return {
complianceType: 'NOT_APPLICABLE',
annotation: 'The configuration item is not recorded in this region and need not be validated',
};
}

for (const existingTag of existingTags) {
if (!existingTag) {
continue;
}
if (existingTag.key == tagKey && existingTag.value == requiredQAConfigID) {
return {
complianceType: 'COMPLIANT',
annotation: 'The IAM Role is complaint and has the expected tag ' + tagKey,
};
}
}
} else {
return {
complianceType: 'NOT_APPLICABLE',
annotation: 'The configuration item is not recorded in this region and need not be validated',
};
}

return {
complianceType: 'NON_COMPLIANT',
annotation: 'The IAM Role does not have the required tag',
};
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::aws-quicksetup-patchpolicy-*"
}
]
}
65 changes: 65 additions & 0 deletions reference-artifacts/ssm-documents/ssm-patching-role-tagging.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
description: Updates the ASEA Role
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
RoleId:
type: String
description: (Required) The name of the role to update
QSConfigID:
type: String
description: (Required) The QSConfigID
AutomationAssumeRole:
type: String
description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
default: ''
mainSteps:
- name: LookupRole
action: 'aws:executeScript'
inputs:
Runtime: python3.8
Handler: getRoleName
InputPayload:
roleId: '{{RoleId}}'
Script: |-
import boto3
import json

iam = boto3.client('iam')

def getRoleName(event, context):
paginator = iam.get_paginator('list_roles')
page_iterator = paginator.paginate()

returnVal = {
'RoleId': '',
'RoleName': ''
}

for role_page in page_iterator:
for role in role_page['Roles']:
if role['RoleId'] == event['roleId']:
returnVal['RoleId'] = role['RoleId']
returnVal['RoleName'] = role['RoleName']

return returnVal

return returnVal


outputs:
- Name: Payload
Selector: $.Payload
Type: StringMap
- Name: RoleName
Selector: $.Payload.RoleName
Type: String
- name: PutTagOnRole
action: 'aws:executeAwsApi'
inputs:
Service: iam
Api: TagRole
RoleName: '{{LookupRole.RoleName}}'
Tags:
- Key: 'QSConfigId-{{QSConfigID}}'
Value: '{{QSConfigID}}'
isEnd: true
2 changes: 2 additions & 0 deletions src/mkdocs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# python
env/
7 changes: 7 additions & 0 deletions src/mkdocs/docs/faq/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,13 @@

Additional endpoints may exist in other AWS regions. Any endpoint can be added to any Accelerator configuration file, as long as it follows the standardized endpoint naming convention (e.g. com.amazonaws.{region}.{service}).


??? faq "1.6.18. How can centralized EC2 patch management be deployed?"

#### How can centralized EC2 patch management be deployed?

With Quick Setup, a capability of AWS Systems Manager, you can create patch policies powered by Patch Manager. A patch policy defines the schedule and baseline to use when automatically patching your Amazon Elastic Compute Cloud (Amazon EC2) instances and other managed nodes. This solution needs modification to deploy into the ASEA. See the guide [here](https://github.com/aws-samples/aws-secure-environment-accelerator/blob/v1.5.7/src/mkdocs/docs/guides/ssm-quick-setup-patching/ssm-quick-setup-patching-configuration.md) to learn how.

## 1.7. Network Architecture

??? faq "1.7.1. We want to securely connect our on-premises networks/datacenters to our AWS Cloud PBMM tenancy, what does AWS you recommend?"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# ASEA - SSM Quick Setup Patching

[Configure AWS SSM Quick Setup Patching in the ASEA](ssm-quick-setup-patching-configuration.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 1. ASEA Configuration for AWS Systems Manager Quick Setup patch policy

## 1.1. Overview

With Quick Setup, a capability of AWS Systems Manager, you can create patch policies powered by Patch Manager. A patch policy defines the schedule and baseline to use when automatically patching your Amazon Elastic Compute Cloud (Amazon EC2) instances and other managed nodes. Using a single patch policy configuration, you can define patching for all accounts in multiple AWS Regions in your organization, for only the accounts and Regions you choose, or for a single account-Region pair.

Beginning December 22, 2022, Patch Manager offers a new, recommended method to configure patching for your organization and AWS accounts through the use of patch policies.

A patch policy is a configuration you set up using Quick Setup. Patch policies provide more extensive and more centralized control over your patching operations than is available with previous methods of configuring patching. Patch policies can be used with all operating systems supported by Patch Manager, including supported versions of Linux, macOS, and Windows Server.

Reference: https://docs.aws.amazon.com/systems-manager/latest/userguide/patch-manager-policies.html, https://docs.aws.amazon.com/systems-manager/latest/userguide/quick-setup-patch-manager.html

## 1.2 Configuration Overview

> The Quick Setup patch policy, described on this page, should only be configured AFTER a successful ASEA installation.

The Quick Setup patch policy is configured within the AWS Systems Manager console. The choices made in the configuration are used as inputs into two CloudFormation Stack Sets: Management ('MA'), and Target Accounts ('TA'). There are a few challenges that restrict the deployment and usage of the Quick Setup within the ASEA; thus, the purpose of creating this content. The challenges are:
- The 'TA' Stack Set hardcodes a Retention on CloudWatch Log (CWL) Groups. CWL Groups are protected by the ASEA SCPs, so this StackSet deployment fails in its default configuration.
- The patch policy configuration, from the Quick Setup, is saved in a S3 bucket, and is used by EC2 SSM Patching. Therefore, the EC2 IAM Instance Profile Roles must have S3 GetObject permissions on this specific S3 bucket.
- That S3 bucket has a resource policy that denies all GetObject requests if the Role does not have a specific Tag and Tag value. Today, the ASEA config lacks the ability to apply tags to IAM Roles. As an example, the default ASEA configuration deploys 'EC2-Default-SSM-AD-Role' that would need Tags and S3:GetObject permissions.

The solution, described in detail below, includes the following:
- Manual modification of the 'TA' StackSet template to remove the hardcoded CWL retenion.
- The creation of a policy, which contains a specific S3:GetObject, that is configured on IAM Roles.
- The creation of a custom AWS Config Rule that inspects Tags on specific IAM Roles. If a target role does not have the specific Quick Setup patch policy Tag, the Role will be 'Non-Compliant'.
- The creation of a SSM Document that can apply Tags to IAM Roles. This is used to auto-remediate a 'Non-Compliant' role detected by the previous custom AWS Config Rule.



## 1.2 Deployment

### 1.2.1 Quick Setup Patch Policy

The following steps have been taken from the documentation [here](https://docs.aws.amazon.com/systems-manager/latest/userguide/quick-setup-patch-manager.html) with modifications.

1. In the Management Account, open the AWS Systems Manager console at https://console.aws.amazon.com/systems-manager/.
2. In the navigation pane, choose **Quick Setup**.
3. On the **Patch Manager** card, choose **Create**.
4. For **Configuration name**, enter a name to help identify the patch policy.
5. In the **Scanning and installation** section, under **Patch operation**, choose whether the patch policy will **Scan** the specified targets or **Scan and install** patches on the specified targets.
6. Under **Scanning schedule**, choose **Use recommended defaults** or **Custom scan schedule**. The default scan schedule will scan your targets daily at 1:00 AM UTC.
7. If you chose **Scan and install**, choose the **Installation schedule** to use when installing patches to the specified targets. If you choose **Use recommended defaults**, Patch Manager will install weekly patches at 2:00 AM UTC on Sunday.
8. In the **Patch baseline** section, choose the patch baselines to use when scanning and updating your targets.
9. In the **Patching log storage** section, select **Write output to S3 bucket** to store patching operation logs in an Amazon S3 bucket.
10. Create a S3 bucket with SSE encryption. Choose **Browse S3** to select the bucket that will be used to configure output patching logs. Note: The bucket you select here is just to progress past the installation; it will be switched to another bucket in later steps.
11. In the Targets section, choose one of the following to identify the accounts and Regions for this patch policy operation.
1. Use **Target OUs** and specify OUs such as 'Dev', 'Test', 'Prod'
2. Use **Target Regions** and only select the needed regions (e.g. ca-central-1)
12. For **Choose how you want to target instances**, choose **All managed nodes**
13. In the **Rate control** section, leave the defaults or change as desired
14. **Unselect** the **Add required IAM policies to existing instance profiles attached to your instances** check box.
15. Choose **Create**


### 1.2.2 Modify the Quick Setup Target Account StackSet Template

Review the CloudFormation Stack Sets, and wait for the 'AWS-QuickSetup-PatchPolicy-TA-...' StackSet to fail.

1. Click on the 'AWS-QuickSetup-PatchPolicy-TA-...' StackSet, and click the **Template** tab.
2. Click the **Copy to clipboard** button
3. Paste the content into a text editor
4. Search for **RetentionInDays** properties on the 'AWS::Logs::LogGroup' resources. Remove all instances of this property and **Save** the file
5. Click on the 'AWS-QuickSetup-PatchPolicy-TA-...' StackSet, and click the **StackSet info** tab.
6. Copy & Paste all the ID's within the **Organziational unit IDs** to a text file, as this will be needed later.
7. From the **Actions** dropdown, choose **Edit StackSet details**
8. Click **Replace current template** and follow the steps to upload the modified saved template from step 4.
9. Accept all defaults until **Step 2**, and update the following parameters:
1. **OutputS3BucketName** -> The Central Log Archive S3 bucket in the logging account. Example, "asea-logarchive-phase0-cacentral1-lgh04fj6ulma"
2. **OutputS3KeyPrefix** -> Enter "ssm-patching"
10. Accept all other defaults and progress until **Step 4 - Set deployment options**
11. The **Organizationl units (OU)** does not maintain the original values. Add each value that was copied in step 6.
12. Specify the same region(s) used in the original configuration (e.g. ca-central-1)
13. Accept all other defaults, and deploy the StackSet update

Review the CloudFormation Stack Sets, and wait for the 'AWS-QuickSetup-PatchPolicy-MA-...' StackSet to succeed.

1. Click on the 'AWS-QuickSetup-PatchPolicy-MA-...' StackSet, and from the **Actions** dropdown, choose **Edit StackSet details**
2. Accept all defaults until **Step 2**, and update the following parameters:
1. **OutputS3BucketName** -> The Central Log Archive S3 bucket in the logging account. Example, "asea-logarchive-phase0-cacentral1-lgh04fj6ulma"
2. **OutputS3KeyPrefix** -> Enter "ssm-patching"
3. Accept all other defaults, and deploy the StackSet update

The StackSets should be successfully deployed, and you can return to the Quick Setup Patch Policy to see the dashboard showing Success.


### 1.2.3 ASEA Configuration file updates

> This section assumes v1.5.7 or greater as it includes the permission policy, ssm document, and custom config rule. Note that these can be manually uploaded to the config S3 bucket, and thus available to older ASEA versions. If applying to a previous version, make sure to copy the following files, found in the reference-artifacts folder, to your config S3 bucket: ``config-rules/ssm-patching-role-tags.zip``, ``iam-policy/ssm-patching-quick-setup-s3-permissions.txt``, and ``ssm-documents/ssm-patching-role-tagging.yaml``


1. Click on the 'AWS-QuickSetup-PatchPolicy-TA-...' StackSet, and click the **Parameters** tab.
2. Locate and record the value for the **QSConfigurationId**

3. Review the sample configuration file, **config.SSM-Patching-example**, found in **reference-artifacts/SAMPLE_CONFIGS/**

4. Compare the file to the sample, **config.example.json**

5. Note how the SSM Document is registered and refereced in target OUs. Adjust as needed.

6. Note how the new IAM Policy is applied to different Roles. Adjust as necessary.

7. Review and adjust the custom AWS Config Rule. The value record from step 1, is needed. Replace the **"*** REPLACE AFTER QUICK SETUP ***"** with the value. It should be a 5 characters alphanumeric string such as **vair8** or **rfnce**.

```
{
"name": "SSM-PATCHING-ROLE-TAGS",
"type": "custom",
"resource-types": ["AWS::IAM::Role"],
"runtime": "nodejs16.x",
"parameters": {
"RoleNames": "EC2-Default-SSM-AD-Role, ${ACCELERATOR_PREFIX_ND}-RDGW-Role, ${ACCELERATOR_PREFIX_ND}-Rsyslog-Role",
"QSConfigID": "*** REPLACE AFTER QUICK SETUP ***",
"ResourceId": "RESOURCE_ID"
},
"remediation-action": "SSM-Patching-Role-Tagging",
"remediation": true,
"remediation-params": {
"RoleId": "RESOURCE_ID",
"QSConfigID": "*** REPLACE AFTER QUICK SETUP ***"
}
}
```

8. Commit the changes to the Config file, and run the State Machine



### 1.2.4 Post Deployment Checks

After the State Machine has completed, log into a workload account within an OU where the solution was expected to be deployed.

1. Launch an EC2
1. Name it **Test**
2. Ensure that the **EC2-Default-SSM-AD-Role** is selected as the IAM Profile
2. Open the AWS Systems Manager console at https://console.aws.amazon.com/systems-manager/.
3. Click on the **Documents** link in the **Shared Resources** left navigation.
4. Click on the **Shared with me** tab, and confirm that **ASEA-SSM-Patching-Role-Tagging** exists.
5. Click on the **State Manager** link in the **Node Management** left navigation.
6. Monitor the AWS-QuickSetup-PatchPolicy-* Assocations. They should succeed once their scheduled time triggers the action. A common failed execution is the missing required tags on the IAM Role.
7. Open the AWS IAM console at https://console.aws.amazon.com/iam/ and navigate to Roles.
8. Find the **EC2-Default-SSM-AD-Role** role, and validate the the **SSM-Pathcing-S3-Policy** exists.
9. Review the **Tags** tab, and most likely there will only be 2. The custom AWS Config Rule hasn't triggered.
10. Open the AWS Config console at https://console.aws.amazon.com/config/
11. Click on **Rules** and search for **ASEA-SSM-PATCHING-ROLE-TAGS**. Inspect the rule and confirm that the **Remediation action** exists.