[備忘録]個人用AWSアカウントを作成したときにやったこと
大半はこちらとこちらを参考にさせてもらった。
その上で、CFnで行ったことや他に取り入れたことについて残す。
Amazon SNSのトピック作成
AWS BudgetsとAmazon GuardDutyが通知に使用するSNSトピックを作成した。
Topic:
Type: AWS::SNS::Topic
Properties:
DisplayName: aws-notification
Subscription:
- Endpoint: <YOUR_MAIL_ADDRESS>
Protocol: email
TopicName: <YOUR_TOPIC_NAME>
TopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: "budgets"
Effect: "Allow"
Principal:
Service: !Sub "budgets.${AWS::URLSuffix}"
Action:
- "sns:Publish"
Resource:
- !Ref Topic
- Sid: "events"
Effect: "Allow"
Principal:
Service: !Sub "events.${AWS::URLSuffix}"
Action:
- "sns:Publish"
Resource:
- !Ref Topic
Topics:
- !Ref Topic
AWS Budgetsの設定
予算(BudgetLimit
)に対して、
- 実際の支出(
NotificationType: ACTUAL
)が70%が超えた時 - 実際の支出(
NotificationType: ACTUAL
)が100%が超えた時 - 支出の予想(
NotificationType: FORECASTED
)が100%が超えた時
上記3パターンで通知を設定した。
Budget:
Type: AWS::Budgets::Budget
Properties:
Budget:
BudgetLimit:
Unit: USD
Amount: <YOUR_MAXIMUM_BUDGET>
BudgetName: monthly
BudgetType: COST
TimeUnit: MONTHLY
NotificationsWithSubscribers:
- Notification:
ComparisonOperator: GREATER_THAN
NotificationType: ACTUAL
Threshold: 70
ThresholdType: PERCENTAGE
Subscribers:
- Address: !Ref Topic
SubscriptionType: SNS
- Notification:
ComparisonOperator: GREATER_THAN
NotificationType: ACTUAL
Threshold: 100
ThresholdType: PERCENTAGE
Subscribers:
- Address: !Ref Topic
SubscriptionType: SNS
- Notification:
ComparisonOperator: GREATER_THAN
NotificationType: FORECASTED
Threshold: 100
ThresholdType: PERCENTAGE
Subscribers:
- Address: !Ref Topic
SubscriptionType: SNS
Amazon GuardDutyの設定
脅威が検知された(GuardDuty Finding
)時にSNSで通知するよう設定した。
EKSは現状使用するつもりが無いため、丸っと無効化した。
GuardDuty:
Type: AWS::GuardDuty::Detector
Properties:
Enable: true
Features:
- Name: EBS_MALWARE_PROTECTION
Status: ENABLED
- Name: EKS_AUDIT_LOGS
Status: DISABLED
- Name: LAMBDA_NETWORK_LOGS
Status: ENABLED
- Name: RDS_LOGIN_EVENTS
Status: DISABLED
- Name: RUNTIME_MONITORING
Status: DISABLED
- Name: S3_DATA_EVENTS
Status: ENABLED
FindingPublishingFrequency: SIX_HOURS
GuardDutyFindingEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.guardduty
detail-type:
- GuardDuty Finding
Name: GuardDuty-Finding-Event
Targets:
- Arn: !Ref Topic
Id: SNS
AWS CloudTrailの設定
保存用のS3バケットは特に何も考えずにサーバーサイド暗号化(ServerSideEncryptionConfiguration
)して、保存期間は1年(ExpirationInDays: 365
)にしておいた。
※保存にかかる費用があまりかからないようであれば見直す。
また、証跡になるものなので、オブジェクトロックを有効化(ObjectLockEnabled: true
)しておいた。
バケットポリシーに関してはこちらを参考にした。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AWSCloudTrailAclCheck20150319", "Effect": "Allow", "Principal": {"Service": "cloudtrail.amazonaws.com"}, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::amzn-s3-demo-bucket", "Condition": { "StringEquals": { "aws:SourceArn": "arn:aws:cloudtrail:region:myAccountID:trail/trailName" } } }, { "Sid": "AWSCloudTrailWrite20150319", "Effect": "Allow", "Principal": {"Service": "cloudtrail.amazonaws.com"}, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/[optionalPrefix]/AWSLogs/myAccountID/*", "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control", "aws:SourceArn": "arn:aws:cloudtrail:region:myAccountID:trail/trailName" } } } ] }
念のためオブジェクトや設定の変更権限はDenyしておいたが、オブジェクトロックはコンプライアンスモードなので不要だったかもしれない。
また、aws:SourceArn
を決め打ちにしたかったが、
- 先に
AWS::CloudTrail::Trail
を作成する→バケットポリシーで許可が無いため作成に失敗する。 - 先に
AWS::S3::BucketPolicy
を作成する→AWS::CloudTrail::Trail
の作成がまだ終わっていないため、参照出来ない。
というジレンマがあり、妥協してStringLike
とワイルカードの併用に落ち着いた。
TrailStorageBucket:
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Type: AWS::S3::Bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: <YOUR_BUCKET_NAME>
LifecycleConfiguration:
Rules:
- ExpirationInDays: 365
NoncurrentVersionExpiration:
NoncurrentDays: 365
Status: Enabled
ObjectLockConfiguration:
ObjectLockEnabled: Enabled
Rule:
DefaultRetention:
Days: 365
Mode: COMPLIANCE
ObjectLockEnabled: true
VersioningConfiguration:
Status: Enabled
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref TrailStorageBucket
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Deny"
Principal:
AWS: "*"
Action:
- "s3:DeleteBucket"
- "s3:DeleteBucketPolicy"
- "s3:PutBucketObjectLockConfiguration"
- "s3:PutBucketPolicy"
- "s3:PutEncryptionConfiguration"
- "s3:PutLifecycleConfiguration"
Resource:
- !GetAtt TrailStorageBucket.Arn
- Effect: "Deny"
Principal:
AWS: "*"
Action:
- "s3:DeleteObject"
- "s3:DeleteObjectVersion"
Resource:
- !Sub "${TrailStorageBucket.Arn}/AWSLogs/${AWS::AccountId}/*"
- Effect: "Allow"
Principal:
Service: !Sub "cloudtrail.${AWS::URLSuffix}"
Action:
- "s3:GetBucketAcl"
Resource:
- !GetAtt TrailStorageBucket.Arn
Condition:
StringLike:
aws:SourceArn: !Sub "arn:${AWS::Partition}:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/*"
- Effect: "Allow"
Principal:
Service: !Sub "cloudtrail.${AWS::URLSuffix}"
Action:
- "s3:PutObject"
Resource:
- !Sub "${TrailStorageBucket.Arn}/AWSLogs/${AWS::AccountId}/*"
Condition:
StringLike:
s3:x-amz-acl: "bucket-owner-full-control"
aws:SourceArn: !Sub "arn:${AWS::Partition}:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/*"
CloudTrail:
Type: AWS::CloudTrail::Trail
Properties:
IncludeGlobalServiceEvents: true
IsLogging: true
IsMultiRegionTrail: true
S3BucketName: !Ref TrailStorageBucket
TrailName: default
DependsOn: BucketPolicy
Permissions Boundary用のIAMポリシーの作成
これまでに作成したAWSアカウントを保護するためのリソースに対して、一切の変更・削除を出来ないようにする。
また、他のIAMユーザーやIAMロールを使用して自身の権限をエスカレーション出来ないようにもする。
※sts:AssumeRole
についても制限が必要そうなので調査中
権限の許可は通常のIAMポリシーとPermissions Boundary用ポリシーの両方で許可されている必要があるため、本当に拒否したい事以外は許可するようにした。
※その他の細かい制御は通常のIAMポリシーで行う
AccountProtectionPermissionsBoundaryPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: AccountProtectionPermissionsBoundary
PolicyDocument:
Version: "2012-10-17"
Statement:
# ----- これまで作成したリソースの変更を禁止 -----
- Effect: "Deny"
Action:
- "sns:Unsubscribe"
Resource: "*"
Condition:
StringEquals:
aws:ResourceTag/aws:cloudformation:stack-id: !Ref AWS::StackId
- Effect: "Deny"
Action:
- "sns:DeleteTopic"
- "sns:RemovePermission"
- "sns:SetTopicAttributes"
Resource:
- !Ref Topic
- Effect: "Deny"
Action:
- "guardduty:DeleteDetector"
- "guardduty:UpdateDetector"
Resource:
- !Sub "arn:${AWS::Partition}:guardduty:${AWS::Region}:${AWS::AccountId}:detector/${GuardDuty}"
- Effect: "Deny"
Action:
- "events:DeleteRule"
- "events:DisableRule"
- "events:PutRule"
- "events:RemoveTargets"
Resource:
- !GetAtt GuardDutyFindingEventRule.Arn
- Effect: "Deny"
Action:
- "cloudtrail:DeleteTrail"
- "cloudtrail:StopLogging"
- "cloudtrail:UpdateTrail"
Resource:
- !GetAtt CloudTrail.Arn
- Effect: "Deny"
Action:
- "iam:CreatePolicyVersion"
- "iam:DeletePolicy"
- "iam:DeletePolicyVersion"
- "iam:SetDefaultPolicyVersion"
Resource:
- !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/AccountProtectionPermissionsBoundary"
# ----- このPermissions Boundary用ポリシーの強制 -----
- Effect: "Deny"
Action:
- "iam:CreateUser"
- "iam:DeleteUserPolicy"
- "iam:PutUserPermissionsBoundary"
- "iam:PutUserPolicy"
- "iam:UpdateUser"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/*"
Condition:
ArnNotEquals:
iam:PermissionsBoundary: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/AccountProtectionPermissionsBoundary"
- Effect: "Deny"
Action:
- "iam:DeleteUserPermissionsBoundary"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/*"
Condition:
ArnEquals:
iam:PermissionsBoundary: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/AccountProtectionPermissionsBoundary"
- Effect: "Deny"
Action:
- "iam:CreateRole"
- "iam:DeleteRolePolicy"
- "iam:PutRolePermissionsBoundary"
- "iam:PutRolePolicy"
- "iam:UpdateRole"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*"
Condition:
ArnNotEquals:
iam:PermissionsBoundary: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/AccountProtectionPermissionsBoundary"
- Effect: "Deny"
Action:
- "iam:DeleteRolePermissionsBoundary"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*"
Condition:
ArnEquals:
iam:PermissionsBoundary: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/AccountProtectionPermissionsBoundary"
# ----- このスタックへの操作を禁止 -----
- Effect: "Deny"
Action:
- "cloudformation:DeleteStack"
- "cloudformation:UpdateStack"
Resource:
- !Ref AWS::StackId
# ----- 本当に禁止にしたいこと以外は許可 -----
- Effect: "Allow"
Action: "*"
Resource: "*"
その他
MFA強制用のIAMポリシー
こちらを参考に設定した。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListActions", "Effect": "Allow", "Action": [ "iam:ListUsers", "iam:ListVirtualMFADevices" ], "Resource": "*" }, { "Sid": "AllowUserToCreateVirtualMFADevice", "Effect": "Allow", "Action": [ "iam:CreateVirtualMFADevice" ], "Resource": "arn:aws:iam::*:mfa/*" }, { "Sid": "AllowUserToManageTheirOwnMFA", "Effect": "Allow", "Action": [ "iam:EnableMFADevice", "iam:GetMFADevice", "iam:ListMFADevices", "iam:ResyncMFADevice" ], "Resource": "arn:aws:iam::*:user/${aws:username}" }, { "Sid": "AllowUserToDeactivateTheirOwnMFAOnlyWhenUsingMFA", "Effect": "Allow", "Action": [ "iam:DeactivateMFADevice" ], "Resource": [ "arn:aws:iam::*:user/${aws:username}" ], "Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } } }, { "Sid": "BlockMostAccessUnlessSignedInWithMFA", "Effect": "Deny", "NotAction": [ "iam:CreateVirtualMFADevice", "iam:EnableMFADevice", "iam:ListMFADevices", "iam:ListUsers", "iam:ListVirtualMFADevices", "iam:ResyncMFADevice" ], "Resource": "*", "Condition": { "BoolIfExists": { "aws:MultiFactorAuthPresent": "false" } } } ] }
付け加えた点として、MFAが有効でないときの許可(NotAction
で設定している部分)にiam:ChangePassword
とiam:GetAccountPasswordPolicy
を追加した。
そうしないと、初回ログイン時のパスワード変更が失敗してしまう。
MultiFactorAuthEnforcementPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: MultiFactorAuthEnforcementPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Deny"
NotAction:
- "iam:ChangePassword"
- "iam:CreateVirtualMFADevice"
- "iam:EnableMFADevice"
- "iam:GetAccountPasswordPolicy"
- "iam:ListMFADevices"
- "iam:ListUsers"
- "iam:ListVirtualMFADevices"
- "iam:ResyncMFADevice"
Resource: "*"
Condition:
BoolIfExists:
aws:MultiFactorAuthPresent: "false"
- Effect: "Allow"
Action:
- "iam:ListUsers"
- "iam:ListVirtualMFADevices"
Resource: "*"
- Effect: "Allow"
Action:
- "iam:CreateVirtualMFADevice"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:mfa/*"
- Effect: "Allow"
Action:
- "iam:EnableMFADevice"
- "iam:GetMFADevice"
- "iam:ListMFADevices"
- "iam:ResyncMFADevice"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/${!aws:username}"
- Effect: "Allow"
Action:
- "iam:DeactivateMFADevice"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/${!aws:username}"
Condition:
Bool:
aws:MultiFactorAuthPresent: "true"
パスワード変更及びアクセスキー発行用のポリシー
こちらとこちらを参考に、自身のパスワードやアクセスキーなどの認証情報を自由にさわれるようにした。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iam:GetAccountPasswordPolicy", "Resource": "*" }, { "Effect": "Allow", "Action": "iam:ChangePassword", "Resource": "arn:aws:iam::*:user/${aws:username}" } ] }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "CreateOwnAccessKeys", "Effect": "Allow", "Action": [ "iam:CreateAccessKey", "iam:GetUser", "iam:ListAccessKeys", "iam:TagUser" ], "Resource": "arn:aws:iam::*:user/${aws:username}" } ] }
{ "Version": "2012-10-17", "Statement": [ { "Sid": "ManageOwnAccessKeys", "Effect": "Allow", "Action": [ "iam:CreateAccessKey", "iam:DeleteAccessKey", "iam:GetAccessKeyLastUsed", "iam:GetUser", "iam:ListAccessKeys", "iam:UpdateAccessKey", "iam:TagUser" ], "Resource": "arn:aws:iam::*:user/${aws:username}" } ] }
OwnCredentialsAccessPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
ManagedPolicyName: OwnCredentialsAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "iam:GetAccountPasswordPolicy"
Resource: "*"
- Effect: "Allow"
Action: "iam:ChangePassword"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/${!aws:username}"
- Effect: "Allow"
Action:
- "iam:CreateAccessKey"
- "iam:DeleteAccessKey"
- "iam:GetAccessKeyLastUsed"
- "iam:GetUser"
- "iam:ListAccessKeys"
- "iam:UpdateAccessKey"
- "iam:TagUser"
Resource: !Sub "arn:${AWS::Partition}:iam::${AWS::AccountId}:user/${!aws:username}"
AWSアカウントのエイリアス設定
AccountAlias:
Type: AWS::SupportApp::AccountAlias
Properties:
AccountAlias: <YOUR_ACCOUNT_ALIAS>
Discussion