こんにちは、IT 基盤部髙橋です。
DeNA が提供するエンタメ系やヘルスケア系のサービスのインフラを見ており、そのグループのマネージャをしています。
先日 AWS Loft Tokyo で DeNA における AWS セキュリティについて発表してきたので、発表では述べられなかった具体的な設定についていくつか記載します。
AWS アカウント管理
AWS アカウント管理を効率的に行うために、スライドの中でいくつかの施策を挙げています。 その中の一部をコマンド例を交えて紹介します。
AWS Organizations を利用したマルチアカウント管理
AWS Organizations の特徴としては以下のようなものが挙げられます。
- アカウントの一元管理
- OU (Organization Unit) を用いた階層的なグループ化も可能
- 一括請求 (Consolidated Billing)
- アカウントの請求と支払いを統合
- リザーブドインスタンスの共有
- 他のアカウントで購入したリザーブドインスタンスを共有することができる
- サービスコントロールポリシー (SCP) の利用
- Organization 配下の各 AWS アカウント (メンバーアカウント) の権限を指定できる
また AWS Organizations を利用すればコマンドで AWS アカウントを作成することが可能になります。
連絡先情報やクレジットカード情報は Organization マスターアカウントの情報が引き継がれます。
--role-name
には作成されるアカウントへの AdministratorAceess 権限を持つロール名を指定します。デフォルトでは以下に記載している通り OrganizationAccountAccessRole
という名前になります。
--iam-user-access-to-billing
には IAM ユーザーに請求情報へのアクセスを許可する場合は ALLOW
を、拒否する場合は DENY
を指定してください。
aws organizations create-account \
--email ${EMAIL} \
--account-name ${ACCOUNT_NAME} \
--role-name OrganizationAccountAccessRole \
--iam-user-access-to-billing ALLOW
{
"CreateAccountStatus": {
"RequestedTimestamp": 1564398749.614,
"State": "IN_PROGRESS",
"Id": "car-01234567890abcdefghijklmnopqrstu",
"AccountName": "sample-account1"
}
}
アカウント作成の状況は以下のコマンドで確認することができます。
State
の値が SUCCEEDED
になるまで定期的に監視すれば、後続の作業も自動化できます。
aws organizations describe-create-account-status \
--create-account-request-id ${ACCOUNT_ID}
{
"CreateAccountStatus": {
"AccountId": "123456789012",
"State": "SUCCEEDED",
"Id": "car-01234567890abcdefghijklmnopqrstu",
"AccountName": "sample-account1",
"CompletedTimestamp": 1564398812.234,
"RequestedTimestamp": 1564398749.696
}
}
AWS アカウント作成時の初期設定や設定変更方法の整備
AWS アカウントを作成するときには同時に各アカウントに必要な初期設定もしています。
aws sts assume-role
コマンドを利用して設定先アカウントの AdministratorAccess 権限を取得します。
ACCOUNT_ID
には上記の出力結果から得られたものを入れます。
--role-session-name
は権限を得たロールのセッションの識別子のようなものでここでは適当な値を入れておきます。
aws sts assume-role \
--role-arn arn:aws:iam::${ACCOUNT_ID}:role/OrganizationAccountAccessRole \
--role-session-name "RoleSession1"
上記コマンドで得られた情報から AccessKeyId
SecretAccessKey
SessionToken
の値を以下のように環境変数に設定します。
export AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPQRST
export AWS_SECRET_ACCESS_KEY=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN
export AWS_SESSION_TOKEN=abcdefghijk...<remainder of security token>
まず以下のようにして作成しようとしているロールが存在するか判定します。
ROLE_NAME
には作成したいロールの名前を入れてください。
aws iam get-role --role-name ${ROLE_NAME}
IAM ロールがまだなければ作成をします。
--assume-role-policy-document
で信頼関係の内容を記載した json 形式のファイルを指定します。
aws iam create-role --role-name ${ROLE_NAME} \
--assume-role-policy-document file://path/to/${ROLE_NAME}-Trust-Policy.json
次に IAM ポリシーの作成をします。
POLICY_NAME
には作成したいポリシーの名前を入れてください。
--policy-document
でポシリーの内容を記載した json 形式のファイルを指定します。
path/to/${ROLE_NAME}-Policy.json
には適切なファイルパスを指定してください。
aws iam create-policy --policy-name ${POLICY_NAME} \
--policy-document file://path/to/${ROLE_NAME}-Policy.json
作成した IAM ロールに先ほど作成した IAM ポリシーをアタッチします。
aws iam attach-role-policy --role-name ${ROLE_NAME} \
--policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/${POLICY_NAME}
このようにして初期設定に必要なロールやポシリーの作成を繰り返し行います。 その他初期設定として CloudTrail の設定やそのログを保管する S3 Bucket の作成なども DeNA では行っています。
全 AWS アカウントの設定変更に関しては、上記で述べた各アカウントに存在する OrganizationAccountAccessRole
を使い、同じように aws sts assume-role
をして設定変更を行います。
AWS Organizations を使えば全 AWS アカウントのリストを取得することも可能なので、これで取得できた全アカウントに対して操作するようなものを書けばよいでしょう。
aws organizations list-accounts
{
"Accounts": [
{
"Name": "sample-account1",
"Email": "sample-email@dena.jp",
"Id": "123456789012",
"JoinedMethod": "CREATED",
"JoinedTimestamp": 1536059567.45,
"Arn": "arn:aws:organizations::123456789013:account/o-abcdefghij/123456789012",
"Status": "ACTIVE"
},
{
"Name": "sample-account2",
"Email": "sample-email2@dena.jp",
"Id": "123456789013",
"JoinedMethod": "CREATED",
"JoinedTimestamp": 1536059568.45,
"Arn": "arn:aws:organizations::123456789000:account/o-abcdefghij/123456789013",
"Status": "ACTIVE"
},
...
]
}
IAM ユーザー管理
発表の中では社内ディレクトリで管理されるフェデレーティッドユーザーを利用した AWS マネジメントコンソールログインの方法について説明しました。
ID フェデレーションによる AWS マネジメントコンソールログイン
下記は踏み台アカウントから各サービスのアカウントに Switch Role を利用してロールの切り替えを行う図ですが、この時の各アカウントに存在するロールのポリシーと信頼関係について解説します。
踏み台アカウントにある step-service-account1-admin
ロールのポリシーは以下のようにしています。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::*:role/service-account1-admin"
}
}
踏み台アカウントにある step-service-account1-admin
ロールの信頼関係は以下のようにしています。
STEP_ACCOUNT_ID
には踏み台アカウントのアカウント ID を入れてください。
SAML_PROVIDER_NAME
には作成した SAML プロバイダの名前を入れてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${STEP_ACCOUNT_ID}:saml-provider/${SAML_PROVIDER_NAME}"
},
"Action": "sts:AssumeRoleWithSAML",
"Condition": {
"StringEquals": {
"SAML:aud": "https://signin.aws.amazon.com/saml"
}
}
}
]
}
各サービスアカウントにある service-account1-admin
ロールのポリシーは以下のようにしています。(ここでは AdministratorAccess 権限となっています。)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
各サービスアカウントにある service-account1-admin
ロールの信頼関係は以下のようにしています。
STEP_ACCOUNT_ID
には踏み台アカウントのアカウント ID を入れてください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${STEP_ACCOUNT_ID}:role/step-service-account1-admin"
},
"Action": "sts:AssumeRole"
}
]
}
上記は AdministratorAccess 権限についての設定例ですが、ReadOnlyAccess やカスタマイズした権限ももたせることが可能になっています。
AWS セキュリティ監査自動化
発表では AWS セキュリティ監査自動化システムの実装例としていくつか述べました。 ここではさらにどのようなコマンドを使って判定するかを具体的に書いていきたいと思います。
ルートユーザーに対して MFA を有効化すること
概要: 認証情報レポートでルートユーザーに対して mfa_active
の値が true
であるか確認します
まずはレポートの生成をします。
aws iam generate-credential-report
{
"State": "STARTED",
"Description": "No report exists. Starting a new report generation task"
}
次に生成したレポートを取得します。
aws iam get-credential-report
取得された内容は Base64 エンコードされているのでデコードする必要があります。
<root_account>
の行で mfa_active
の値が true
であれば MFA が有効であることになります。
user,arn,user_creation_time,password_enabled,password_last_used,password_last_changed,password_next_rotation,mfa_active,access_key_1_active,access_key_1_last_rotated,access_key_1_last_used_date,access_key_1_last_used_region,access_key_1_last_used_service,access_key_2_active,access_key_2_last_rotated,access_key_2_last_used_date,access_key_2_last_used_region,access_key_2_last_used_service,cert_1_active,cert_1_last_rotated,cert_2_active,cert_2_last_rotated
<root_account>,arn:aws:iam::123456789012:root,2018-06-20T13:38:27+00:00,not_supported,2019-07-02T09:23:21+00:00,not_supported,not_supported,true,false,N/A,N/A,N/A,N/A,false,N/A,N/A,N/A,N/A,false,N/A,false,N/A
...
IAM で利用が完了し使われてないアクセスキーは無効化・削除すること
概要: list-users
でユーザ一覧を出し、 list-access-keys
で Status
が Active
なものの中で、 get-access-key-last-used
から得られる LastUsedDate
が特定の期間内であるか確認します
まずは list-users
で IAM ユーザ一覧の情報を取得します。
aws iam list-users
{
"Users": [
{
"Arn": "arn:aws:iam::123456789012:user/sample-user1",
"UserId": "ABCDEFGHIJKLMNOPQRSTU",
"CreateDate": "2018-07-23T09:37:10Z",
"UserName": "sample-user1",
"Path": "/"
},
{
"Arn": "arn:aws:iam::123456789013:user/sample-user2",
"UserId": "ABCDEFGHIJKLMNOPQRSTV",
"CreateDate": "2018-08-01T11:51:47Z",
"UserName": "sample-user2",
"Path": "/"
},
…
]
}
次に list-access-keys
で Status
の情報を取得します。
--user-name
には上記で取得できたユーザー名を指定します。
aws iam list-access-keys --user-name sample-user1
{
"AccessKeyMetadata": [
{
"AccessKeyId": "ABCDEFGHIJKLMNOPQRST",
"Status": "Active",
"CreateDate": "2019-01-09T08:15:14Z",
"UserName": "sample-user1"
},
{
"AccessKeyId": "ABCDEFGHIJKLMNOPQRSU",
"Status": "Active",
"CreateDate": "2019-07-29T16:35:35Z",
"UserName": "sample-user1"
}
]
}
最後に --access-key-id
でアクセスキー ID を指定してそのキーの LastUsedDate
を求めます。得られた LastUsedDate
が特定の期間内であるか確認します。
aws iam get-access-key-last-used --access-key-id ABCDEFGHIJKLMNOPQRST
{
"AccessKeyLastUsed": {
"Region": "us-east-1",
"LastUsedDate": "2019-01-09T10:52:00Z",
"ServiceName": "iam"
},
"UserName": "sample-user1"
}
ELB のアクセスログを有効化すること
概要: describe-load-balancer-attributes
で access_logs.s3.enabled
の値が true
であるか確認します
aws elbv2
コマンドを使います。
--load-balancer-arn
には情報を取得する LB の ARN を指定します。
aws elbv2 describe-load-balancer-attributes --load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:loadbalancer/app/sample-alb1/abcdefghijklmnop
以下のように色々な値が取れます。今回は access_logs.s3.enabled
の値を確認します。
{
"Attributes": [
{
"Value": "false",
"Key": "access_logs.s3.enabled"
},
{
"Value": "",
"Key": "access_logs.s3.bucket"
},
{
"Value": "",
"Key": "access_logs.s3.prefix"
},
{
"Value": "60",
"Key": "idle_timeout.timeout_seconds"
},
{
"Value": "false",
"Key": "deletion_protection.enabled"
},
{
"Value": "true",
"Key": "routing.http2.enabled"
}
]
}
RDS でインターネットからのアクセスが不要な場合はパブリックアクセシビリティを無効にすること
概要: describe-db-instances
で PubliclyAccessible
が false
であるか確認します
aws rds
コマンドを使います。
--db-instance-identifier
には DB の識別子を指定します。
aws rds describe-db-instances --db-instance-identifier sample-db1
PubliclyAccessible
の値が false
であれば問題ないです。(かなり多くの情報が取れるので省略します。)
{
"DBInstances": [
{
"DBInstanceIdentifier": "sample-db1",
"AvailabilityZone": "ap-northeast-1a",
"DBInstanceClass": "db.m5.large",
"BackupRetentionPeriod": 7,
"Engine": "mysql",
"PubliclyAccessible": true,
...
}
]
}
おわりに
以上、DeNA での AWS アカウント管理とセキュリティ監査自動化について説明してきました。 DeNA ではこれまで以上に大規模に AWS を利用していくために、セキュリティレベルの高い状態をより効率的に構築管理できる方法を日々考えています。
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。