はじめに
AWSにはアカウントやリソースへの脅威検知に対応した、AWS IAM Access Analyzer, AWS Security Hub, Amazon Detective, Amazon Inspector, Amazon GuardDuty, AWS CloudTrail, AWS Config などのサービスが用意されています。
また、AWS Security Hub では、CIS AWS Foundations Standard , Payment Card Industry Data Security Standard , AWS Foundational Security Best Practices Standard などのセキュリティ標準が公開されており、このガイドラインは、AWSアカウントをセキュアに保つために必要なAWSのセキュリティ設定を集めたベストプラクティス集として活用できます。
本記事では、アカウントやリソースへの脅威検知が可能なAWSサービスを有効化するとともに、上記のセキュリティ標準に限りなく準拠することで、セキュアで堅牢なAWSアカウントを実現します。また、これらをお手軽に実現できるCloudFormationテンプレートを公開しています。
このCloudFormationテンプレートの実行はこちらから。
アクセスキーのローテーション
アクセスキー とは、IAM ユーザーまたは ルートユーザー の 長期的な認証情報を指し、AWS SDK や AWS API を実行する際にこのアクセスキーを指定することで、このアクセスキーに許可された権限を実行することができます。したがって、このアクセスキーが外部に流出した場合には、 第三者がアカウントへの永続的アクセスを取得する可能性 があります。そこで、CIS AWS Foundations Benchmark および AWS Foundational Security Best Practices Standard では、
セキュリティ標準 | No. | 内容 |
---|---|---|
CIS AWS Foundations Standard | 1.3 | 90 日間以上使用されていない認証情報は無効にします |
CIS AWS Foundations Standard | 1.4 | アクセスキーは 90 日ごとに更新します |
AWS Foundational Security Best Practices Standard | IAM.3 | IAM ユーザーのアクセスキーは 90 日ごとに更新する必要があります。 |
というガイドラインを規定しており、アクセスキーの定期的なローテーションによって、意図せぬアクセスのリスクを低減するように求めています。
上記ガイドラインに準拠するためには、AWS Config
を用いて、定期的に現在の状態の確認 を行う必要があります。また、上記基準を満たしていないことが判明した場合は、当該のアクセスキーを無効化、もしくは削除 する必要があります。
1. AWS Configの有効化
AWS Config
を設定して、上記ガイドラインに準拠しているかどうかを定期的に確認します。「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート - ①サービスの有効化も合わせてご覧ください。
サービスにリンクされたロールの作成
AWS Config
で使用する Service-Linked Role
を作成します。この Service-Linked Role
は、 AWSリソースへの読み込み権限 と S3への書き込み権限 を Config
に、また、IAMとSystemManagerへの書き込み権限 を Config Remediation
にそれぞれ付与します。
Resources:
ServiceLinkedRoleForConfig:
Type: AWS::IAM::ServiceLinkedRole
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
AWSServiceName: config.amazonaws.com
Description: A service-linked role required for AWS Config to access your resources.
ServiceLinkedRoleForConfigRemediation:
Type: AWS::IAM::ServiceLinkedRole
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
AWSServiceName: remediation.config.amazonaws.com
Description: A service-linked role required for AWS Config Remediation to access your resources.
AWS Configの有効化
AWS Config
の DeliveryChannel
と ConfigurationRecorder
を作成します。
Resources:
ConfigDeliveryChannel:
Type: AWS::Config::DeliveryChannel
Properties:
Name: default
S3BucketName: !Ref S3ForConfig
ConfigConfigurationRecorder:
Type: AWS::Config::ConfigurationRecorder
Properties:
Name: default
RecordingGroup:
AllSupported: true
IncludeGlobalResourceTypes: true
RoleARN: !Sub arn:aws:iam::DefaultSecuritySettings:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
Amazon S3 バケットを作成
設定情報 (履歴ファイルやスナップショット) を保存するために使用する、Amazon S3
バケットと、それに紐づくバケットポリシーを作成します。
Resources:
S3ForConfig:
Type: 'AWS::S3::Bucket'
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Sub defaultsecuritysettings-config-${AWS::Region}-${AWS::AccountId}
LifecycleConfiguration:
Rules:
- Id: ExpirationInDays
ExpirationInDays: 60
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
S3BucketPolicyForConfig:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3ForConfig
PolicyDocument:
Version: 2012-10-17
Id: !Ref S3ForConfig
Statement:
- Effect: Allow
Principal:
Service: config.amazonaws.com
Action:
- 's3:GetBucketAcl'
- 's3:ListBucket'
Resource:
- !GetAtt S3ForConfig.Arn
- Effect: Allow
Principal:
Service: config.amazonaws.com
Action:
- 's3:PutObject'
Resource:
- !Join
- ''
- - !GetAtt S3ForConfig.Arn
- /AWSLogs/
- !Sub ${AWS::AccountId}
- /Config/*
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
- Effect: Deny
Principal: '*'
Action: 's3:*'
Resource:
- !GetAtt S3ForConfig.Arn
- !Join
- ''
- - !GetAtt S3ForConfig.Arn
- /*
Condition:
Bool:
aws:SecureTransport: false
2. AWS Configを用いた定期チェック
AWSによって管理されている AWS Config マネージドルール
の中に、 ACCESS_KEYS_ROTATED
という名称で、アクティブなアクセスキーが指定された日数内にローテーションされるかどうかを確認できるルール が用意されているので、これを追加します。
Resources:
ConfigIamAccessKeysRotated:
DependsOn:
- ConfigConfigurationRecorder
Type: 'AWS::Config::ConfigRule'
Properties:
ConfigRuleName: access-keys-rotated
Description: アクティブなアクセスキーが、maxAccessKeyAge で指定された日数内にローテーションされるかどうかを確認します。
InputParameters:
maxAccessKeyAge: 90
Source:
Owner: AWS
SourceIdentifier: ACCESS_KEYS_ROTATED
上記で設定した AWS Config ルールは定期的に実行され、アカウントがこのルールに準拠しているかどうかの判定が行われます。しかし、これらの設定は、ルールに準拠しているかどうかを判定するだけであるため、もしルールに非準拠であることが判明した場合には、該当するアクセスキーを手動で削除する必要があります。
3. Lambdaを用いたアクセスキーの強制削除
そこで、以下の内容も設定に加えることで、ガイドラインの基準に違反するアクセスキーを強制的に削除 することができます。ただし下記の設定は、ユーザに確認を求めることなく問答無用にアクセスキーを削除してしまう ため、下記設定を加えるかどうかについては 慎重な検討が必要 です。またもしこの設定を適用する場合でも、ご自身のアカウントの運用ポリシーに合った内容に処理を書き換えることをオススメします。
Amazon EventBridgeの追加
AWS Config
が発行する Amazon EventBridge
のうち、AWS Configに非準拠のルールが検知された場合のみを抽出して、後述の アクセスキーを強制削除するLambdaの実行トリガ にします。
CloudWatchEventsForConfigIamAccessKeysRotated:
Type: 'AWS::Events::Rule'
Properties:
Description: EventBridge about Config when IAM Access Keys are rotated.
EventPattern:
source:
- aws.config
detail-type:
- Config Rules Compliance Change
detail:
configRuleName:
- !Ref ConfigIamAccessKeysRotated
messageType:
- ComplianceChangeNotification
newEvaluationResult:
complianceType:
- NON_COMPLIANT
Name: Config
State: ENABLED
Targets:
- Arn: !GetAtt LambdaDeleteExpiredAccessKeys.Arn
Id: lambda
Lambda 関数の追加
アクセスキーを強制削除するLambdaを作成します。このLambdaは、AWS Configから通知された内容が、 アクティブなアクセスキーが指定された日数(=90日)内にローテーションされるかどうかを確認できる、access-keys-rotated
に関連するものであることを確認した上で、作成から90日が経過したアクセスキーのみを削除 します。
LambdaDeleteExpiredAccessKeys:
Type: 'AWS::Lambda::Function'
Properties:
Code:
ZipFile: |
import boto3
import datetime
import time
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(str(event))
if 'detail' in event:
detail = event['detail']
if 'configRuleName' in detail:
# access-keys-rotated
if detail['configRuleName'] == 'access-keys-rotated':
iam = boto3.client('iam')
users = iam.list_users()
for user in users['Users']:
if detail['resourceId'] == user['UserId']:
access_keys = iam.list_access_keys(
UserName=user['UserName']
)
for access_key in access_keys['AccessKeyMetadata']:
create_date = access_key['CreateDate'].timestamp()
now = time.time()
if now - create_date > 60*60*24*90:
response = iam.delete_access_key(
UserName=user['UserName'],
AccessKeyId=access_key['AccessKeyId']
)
Description: 有効期限が過ぎたアクセスキーを削除します
FunctionName: deleteExpiredAccessKeys
Handler: index.lambda_handler
MemorySize: 128
Role: !GetAtt IAMRoleForLambda.Arn
Runtime: python3.7
Tags:
- Key: !Ref TagKey
Value: !Ref TagValue
Timeout: 3
TracingConfig:
Mode: Active
LambdaDeleteExpiredAccessKeysPermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref LambdaDeleteExpiredAccessKeys
Principal: events.amazonaws.com
SourceArn: !GetAtt CloudWatchEventsForConfigIamAccessKeysRotated.Arn
LambdaDeleteExpiredAccessKeysLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${LambdaDeleteExpiredAccessKeys}
RetentionInDays: 60
下記のCloudFormationテンプレートを実行することで、上記設定を含む、 AWS IAM Access Analyzer, AWS Security Hub, Amazon Detective, Amazon Inspector, Amazon GuardDuty, AWS CloudTrail, AWS Config などのサービス全てを有効化することも、今回の設定を含むAWS Configのみを有効化することも可能です。
作成されるAWSサービス | CloudFormationテンプレート |
---|---|
全てのセキュリティサービス | |
AWS Configのみ |
関連リンク
- サービスの有効化 - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- パスワードポリシーの自動修復 - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- モニタリングと通知の設定 - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- アクセスキーのローテーションと削除 - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- 全てのVPCでフローログを有効化する - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- SSHとRDPのアクセスを制限する - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- デフォルトセキュリティグループを無効化する - 「セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート
- S3バケットのサーバサイド暗号化 - セキュアで堅牢なAWSアカウント」を実現する CloudFormationテンプレート