この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
いわさです。
AWSでは、Systems Manager Patch Managerを使うことで、EC2インスタンスへのセキュリティパッチの管理や更新の自動化を行うことが可能です。
ただし、パッチマネージャーの導入を検討する際には、ベースラインをどうするか、パッチ承認をどうするか、インストールのタイミングは、など慎重に検討しなければいけない要素が多いと思います。
そこで、まずはすべてのパッチを対象としたベースラインでスキャンだけしておき、スキャンした結果を週次など定期的にレポートする程度のスモールスタートな方法から始めることにしました。
その上で定期的にレポートを確認し、判断のうえオンデマンドでパッチ適用やベースラインの見直しを行っていきます。
定期スキャン
定期スキャンは、パッチベースラインを作成し、パッチグループとの紐づけを行います。
専用のタグをEC2に付与することでインスタンスをパッチグループ配下で管理することができるようになります。
そしてメンテナンスウィンドウを使って、定期的なスキャンをスケジューリングします。
ベースライン適用はスキャンのみか、スキャン&インストールを選択できます。
今回はスキャンのみなので承認日数は0日にしています。
もしインストールまで行う場合はより承認日数を考えた運用設計が必要ですね。
パッチマネージャーのスキャン状況および結果は次のようにマネジメントコンソール上でレポートとして表示されます。
パッチマネージャー内のレポート内容をS3へエクスポートしつつSNSでの通知を行うことが可能です。
次項ではそのあたりを設定します。
定期レポート
レポート機能は以下の記事でも紹介されています。割と最近のアップデートです。
レポートはスケジュール実行が可能です。
実体としては、EventBridgeでSSM Automationを定期実行しています。
レポートはS3バケットにCSVファイルが出力されます。
Index,Instance ID,Instance name,Instance IP,Platform name,Platform version,SSM Agent version,Patch baseline,Patch group,Compliance status,Compliance severity,Noncompliant Critical severity patch count,Noncompliant High severity patch count,Noncompliant Medium severity patch count,Noncompliant Low severity patch count,Noncompliant Informational severity patch count,Noncompliant Unspecified severity patch count
0,i-002bd55d99254ce3f,,172.31.2.45,Microsoft Windows Server 2019 Datacenter,10.0.17763,3.0.529.0,pb-0bbd976a5e8553e9e,iwapatch,NON_COMPLIANT,UNSPECIFIED,0,0,0,0,0,4
通知にはAmazonSNSを使用しており、Eメールで以下の通知内容が送信されます。
Patch Summary was successfully exported as a CSV file. The file,iwarepo.csv, is located in the following Amazon S3 bucket: iwasa-report-123456789012-patch-report-bucket
CloudFormationテンプレート
定期スキャンと定期レポートでテンプレートを分けています。
SecurityHubなどで管理する場合は定期スキャンのみ使うなどを想定しています。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
PatchGroupName:
Type: String
Description: patch group name
PatchScanSchedule:
Type: String
Default: "cron(0 0 3 ? * * *)"
Description: "patch scan schedule cron expression (JST)"
PatchTargetOperatingSystem:
Type: String
Default: WINDOWS
AllowedValues:
- AMAZON_LINUX
- AMAZON_LINUX_2
- CENTOS
- DEBIAN
- MACOS
- ORACLE_LINUX
- REDHAT_ENTERPRISE_LINUX
- SUSE
- UBUNTU
- WINDOWS
# Metadata:
Description: ""
Resources:
SSMPatchBaseline:
Type: "AWS::SSM::PatchBaseline"
Properties:
Name: !Sub ${AWS::StackName}-fullscan-patchbaseline
OperatingSystem: !Ref PatchTargetOperatingSystem
ApprovalRules:
PatchRules:
- ApproveAfterDays: 0
PatchFilterGroup:
PatchFilters:
- Key: PATCH_SET
Values:
- OS
- Key: PRODUCT
Values:
- "*"
- Key: CLASSIFICATION
Values:
- "*"
- Key: MSRC_SEVERITY
Values:
- "*"
ComplianceLevel: UNSPECIFIED
EnableNonSecurity: false
ApprovedPatchesComplianceLevel: "UNSPECIFIED"
ApprovedPatchesEnableNonSecurity: false
RejectedPatchesAction: "ALLOW_AS_DEPENDENCY"
PatchGroups:
- !Ref PatchGroupName
SSMMaintenanceWindow:
Type: "AWS::SSM::MaintenanceWindow"
Properties:
Name: !Sub ${AWS::StackName}-maintenancewindow
Schedule: !Ref PatchScanSchedule
ScheduleTimezone: "Asia/Tokyo"
Duration: 1
Cutoff: 0
AllowUnassociatedTargets: true
SSMMaintenanceWindowTask:
Type: "AWS::SSM::MaintenanceWindowTask"
Properties:
Name: !Sub ${AWS::StackName}-maintenancewindow-task
WindowId: !Ref SSMMaintenanceWindow
Targets:
-
Key: "WindowTargetIds"
Values:
- !Ref SSMMaintenanceWindowTarget
TaskArn: "AWS-RunPatchBaseline"
ServiceRoleArn: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ssm.amazonaws.com/AWSServiceRoleForAmazonSSM"
TaskType: "RUN_COMMAND"
TaskParameters: {}
Priority: 1
MaxConcurrency: "50"
MaxErrors: "0"
TaskInvocationParameters:
MaintenanceWindowRunCommandParameters:
Parameters:
Operation:
- "Scan"
SnapshotId:
- "{{WINDOW_EXECUTION_ID}}"
TimeoutSeconds: 600
SSMMaintenanceWindowTarget:
Type: "AWS::SSM::MaintenanceWindowTarget"
Properties:
Name: !Sub ${AWS::StackName}-patch-target
WindowId: !Ref SSMMaintenanceWindow
ResourceType: "INSTANCE"
Targets:
-
Key: "tag:Patch Group"
Values:
- !Ref PatchGroupName
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
EMailAddress:
Type: String
Description: Specifies your E-Mail for Patch Scan Report.
ScheduleExpression:
Type: String
Default: "cron(10 18 ? * * *)"
Description: "cron/rate expression by UTC"
ReportName:
Type: String
Description: ""
Description: "The scheduling expression that determines when and how often the rule runs"
Resources:
S3Bucket:
Type: "AWS::S3::Bucket"
Properties:
BucketName: !Sub ${AWS::StackName}-${AWS::AccountId}-patch-report-bucket
BucketEncryption:
ServerSideEncryptionConfiguration:
-
ServerSideEncryptionByDefault:
SSEAlgorithm: "AES256"
BucketKeyEnabled: false
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
-
Id: "auto-delete"
Status: "Enabled"
ExpirationInDays: 400
SNSTopic:
Type: "AWS::SNS::Topic"
Properties:
DisplayName: !Sub ${AWS::StackName}-patch-report-topic
Subscription:
- Endpoint: !Ref EMailAddress
Protocol: email
TopicName: !Sub ${AWS::StackName}-patch-report-topic
SNSTopicPolicy:
Type: "AWS::SNS::TopicPolicy"
Properties:
Topics:
- !Ref SNSTopic
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: "*"
Action:
- SNS:GetTopicAttributes
- SNS:SetTopicAttributes
- SNS:AddPermission
- SNS:RemovePermission
- SNS:DeleteTopic
- SNS:Subscribe
- SNS:ListSubscriptionsByTopic
- SNS:Publish
- SNS:Receive
Resource: !Ref SNSTopic
Condition:
StringEquals:
AWS:SourceOwner: !Ref AWS::AccountId
EventsRule:
Type: "AWS::Events::Rule"
Properties:
Name: !Sub AWS-SystemsManager-PatchManager-PatchReport-${AWS::StackName}
Description: "Schedule recurring patch reporting"
ScheduleExpression: !Ref ScheduleExpression
State: "ENABLED"
EventBusName: "default"
Targets:
- Id: !Sub ${AWS::StackName}-patch-report-target
Arn: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-ExportPatchReportToS3:$DEFAULT"
RoleArn: !GetAtt PatchAutomationRole.Arn
Input: !Sub |
{
"assumeRole": [
"${PatchExportRole.Arn}"
],
"reportName": [
"${ReportName}"
],
"s3BucketName": [
"${S3Bucket}"
],
"targets": [
"instanceids=*"
],
"snsTopicArn": [
"${SNSTopic}"
]
}
PatchExportRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: !Sub ${AWS::StackName}-patch-summary-export-role
AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"ssm.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
MaxSessionDuration: 3600
ManagedPolicyArns:
- !Ref PatchExportPolicy
Description: "Service role for lambda to execute csv export of patch reports"
PatchAutomationRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: !Sub ${AWS::StackName}-patch-automation-role
AssumeRolePolicyDocument: "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"events.amazonaws.com\"},\"Action\":\"sts:AssumeRole\"}]}"
MaxSessionDuration: 3600
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole"
- !Ref PatchAutomationPolicy
Description: "Service role for event bridge to call ssm automation on a schedule"
PatchAutomationPolicy:
Type: "AWS::IAM::ManagedPolicy"
Properties:
ManagedPolicyName: !Sub ${AWS::StackName}-patch-automation-policy
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "ssm:StartAutomationExecution",
"Effect": "Allow",
"Resource": [
"arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-ExportPatchReportToS3:$DEFAULT"
]
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": "${PatchExportRole.Arn}",
"Condition": {
"StringLikeIfExists": {
"iam:PassedToService": "ssm.amazonaws.com"
}
}
}
]
}
PatchExportPolicy:
Type: "AWS::IAM::ManagedPolicy"
Properties:
ManagedPolicyName: !Sub ${AWS::StackName}-patch-summary-export-policy
PolicyDocument: |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketAcl"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"sns:Publish"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"ssm:DescribeInstancePatchStates",
"ssm:DescribeInstancePatches",
"ssm:ListComplianceItems",
"ssm:ListResourceComplianceSummaries",
"ssm:DescribeInstanceInformation",
"ssm:GetInventory",
"ec2:DescribeInstances"
],
"Resource": [
"*"
]
}
]
}
使い方
CloudFormationを実行します。
その後EC2インスタンスにタグを付与します。(キー:Patch Group)
TagEditorなど使うと複数インスタンスへの一括設定ができますので便利です。
注意点など
マネジメントコンソールからレポートのスケジュール機能を作成した場合、必要なロールが自動生成されますが、現時点ではどうやらポリシーが不足したロールが生成されるようでレポートのスケジュールを作成しただけだと定期レポートは動作しません。
よって今回はマネージドポリシーを追加しています。
さいごに
スモールスタートで運用しながらベースラインの見直しをすることを想定しているため、事前定義済みパッチは使いません。
これらの操作はすべてマネジメントコンソールから設定が可能ですが、スモールスタート用に流用しやすくしたかったのでCloudFormationテンプレートにしました。
テンプレートはGitHubリポジトリにも置いておきます。