EC2に脆弱性を仕込んでパッチ適用してみた!
目次
こんにちは!ブログ更新サボり気味な、スカイアーチHRソリューションズのMiyahiraです。
AWSエンジニア経験2年目の私ですが、EC2のパッチ適用を行ったことがありません、、。
なので、今回はEC2に脆弱性を意図的に仕込んで、それを検出し、脆弱性対応としてパッチ適用を行っていきたいと思います!
今回の内容は、書籍「AWSで実践するEC2の脆弱性対応」を参考に行っています。書籍では、脆弱性やパッチ適用ってそもそも何?といったところから記載されているので、ぜひ読んでみてください。
前提事項
本記事は、以下を前提に進めていきます。書籍には、使用するAWSサービスの説明や用途から細かく記載されているので、初心者の方は書籍を購入してみてください!
- 脆弱性、パッチ適用とは何かを理解している
- AWSアカウントを作成済み
- AWSをある程度触ったことがある
- 各AWSサービスの仕様などについては説明しません
全体の流れ
今回行う内容は、以下の流れとなります。
- VPC関連、セキュリティグループの作成
- EC2を作成し、脆弱性を仕込む
- Amazon Inspectorで脆弱性を検出する
- Patch Managerでパッチ適用を行う
環境構築
VPC関連、セキュリティグループの作成
まずはVPC関連のリソースを作成します。CloudFormationテンプレートを作成したので、こちらをデプロイしてください。
作成するリソース | 設定値 |
---|---|
VPC | 10.0.0.0/16 |
パブリックサブネット×1 | 10.0.0.0/24 |
プライベートサブネット×1 | 10.0.10.0/24 |
インターネットゲートウェイ | |
NATゲートウェイ | |
Elastic IPアドレス | NATゲートウェイ用 |
セキュリティグループ | 自身のセキュリティグループのみ通信可 |
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Default: ec2-vulns-handson
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet
Type: String
Default: 10.0.0.0/24
PrivateSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet
Type: String
Default: 10.0.10.0/24
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-vpc
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-IGW
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PublicSubnetCIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PublicSubnet
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: ap-northeast-1a
CidrBlock: !Ref PrivateSubnetCIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PrivateSubnet
NatGatewayEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-NGW
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PublicRoutes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-PrivateRoutes
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
PrivateSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable
SubnetId: !Ref PrivateSubnet
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub ${EnvironmentName}-ec2-sg
GroupName: !Sub ${EnvironmentName}-ec2-sg
VpcId:
!Ref VPC
SecurityGroupIgress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
IpProtocol: -1
GroupId: !Ref SecurityGroup
SourceSecurityGroupId: !Ref SecurityGroup
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
Export:
Name: !Sub ${EnvironmentName}-VPC
PublicSubnet:
Description: A reference to the public subnet
Value: !Ref PublicSubnet
Export:
Name: !Sub ${EnvironmentName}-PublicSubnet
PrivateSubnet:
Description: A reference to the private subnet
Value: !Ref PrivateSubnet
Export:
Name: !Sub ${EnvironmentName}-PrivateSubnet
SecurityGroup:
Description: A reference to the SecurityGroup
Value: !Ref SecurityGroup
Export:
Name: !Sub ${EnvironmentName}-SecurityGroup
脆弱性を仕込んだEC2の作成
次にEC2を作成します。脆弱性を意図的に仕込むために、Apacheの古いバージョンをインストールします。こちらもCloudFormationで脆弱性が仕込まれたEC2を作成できます。
作成するリソース | 設定値 |
---|---|
インスタンスプロファイル | EC2にアタッチ(SSMから接続する用) |
EC2 | AMI:Amazon Linux 2 InstanceType:t2.micro サブネット:プライベートサブネットに配置 キーペア:なし ユーザデータ:Apacheの「2.4.33-2.amzn2.0.2」バージョンをインストール |
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Default: ec2-vulns-handson
EC2ImageId:
Type: String
Default: ami-0f89bdd365c3d966d
EC2InstanceType:
Type: String
Default: t2.micro
Resources:
InstanceProfile:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${EnvironmentName}-InstanceProfileForSSM
Description: EC2 IAM role for SSM access
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Ec2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref InstanceProfile
EC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref EC2InstanceType
ImageId: !Ref EC2ImageId
IamInstanceProfile: !Ref Ec2InstanceProfile
SubnetId:
Fn::ImportValue: !Sub ${EnvironmentName}-PrivateSubnet
SecurityGroupIds:
- Fn::ImportValue: !Sub ${EnvironmentName}-SecurityGroup
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-EC2
UserData:
Fn::Base64: |
#!/bin/bash
sudo su -
yum install httpd-2.4.33-2.amzn2.0.2 -y
systemctl enable httpd.service
systemctl start httpd.service
systemctl status httpd.service
Apacheの確認
セッションマネージャーからEC2に接続し、以下のコマンドを実行してApacheの古いパッケージがインストールされているか確認します。
$ rpm -qa | grep httpd
AMIバックアップの作成
脆弱性にパッチ適用を何度も行えるように、脆弱性を仕込んだEC2のAMIバックアップを作成しておきます。
脆弱性を検出する
Amazon Inspectorを有効化する
Amazon Inspectorの画面⇒「使用を開始する」をクリック⇒「Ianpectorをアクティブ化」をクリック
スキャン結果の確認
Amazon Inspectorの画面⇒検出結果⇒インスタンス別
Inspectorを有効化すると最初のスキャンが開始されるので、完了するまで待ちます。
スキャンが完了するとEC2が表示され、脆弱性の数が表示されます。
EC2インスタンスIDをクリックすると、スキャン結果の詳細が表示されます。
パッチを適用する
先ほどAmazon Inspectorで検出したEC2の脆弱性を、Systems Manager Patch Managerでパッチ適用します。
EC2にタグを付与する
パッチ適用対象インスタンスの紐づけを行うために、EC2にタグを付与します。
タグキー | 値 |
---|---|
Patch Group | ec2-vulns-handson |
パッチマネージャーの設定
パッチマネージャーの画面⇒「概要から開始」をクリック⇒「パッチベースライン」をクリック⇒「パッチベースラインを作成する」をクリック
以下のパラメータを入力します。
項目 | 設定値 |
---|---|
名前 | ec2-vulns-handson-patch-baseline |
説明 | ec2-vulns-handson-patch-baseline |
オペレーティングシステム | Amazon Linux 2 |
製品 | All |
重要度 | All |
自動承認 | 特定の日付までにリリースされたパッチを適用する |
日付の指定 | 実施日の1ヶ月前を入力 |
作成後、「今すぐパッチ適用」をクリックし、画像と同じように設定して、「今すぐパッチ適用」をクリックします。※今回はスキャンのみなので、パッチは適用されません。
パッチベースラインに戻り、作成したパッチベースラインを選択して、アクションからパッチグループの変更を行います。
パッチグループには、先ほどEC2に付与したタグ「Patch Group」の値「ec2-vulns-handson」を入れます。
パッチを適用する
「今すぐ適用」をクリックします。今回はスキャンのみではなくパッチ適用まで行うので、画像を参考に入力してください。
「今すぐパッチ適用」をクリック後、RunCommandを確認すると、「AWS-RunPatchBaseline」というドキュメントが実行されていることが確認できます。
パッチマネージャーの画面でステータスが「Success」となれば、パッチ適用完了です。
パッチ適用の結果確認
Amazon Inspectorで検出結果を確認すると、脆弱性がなくなったことが確認できます。
まとめ
今回はとりあえずパッチ適用の流れが分かればよかったのでだいぶ簡単に行いましたが、実際の運用を考えると、もっと考慮が必要な点があります。
パッチ適用前にバックアップ取得や、適用後の正常性確認、パッチの定期実行などについても考えなければいけません。
ちょっと長くなってしまったので今回は省きます。が、なんと!参考にした書籍「AWSで実践するEC2の脆弱性対応」では実際の運用を考え、Step Functionsでワークフローを作成し、それを定期実行するところまで詳しく書かれていますので、ぜひ読んでみてください!