こんにちは、2019年7月よりトレタにJOINした @aibou です。 本記事はトレタ Advent Calendar 2019の16日目の記事です。
趣味はNFL観戦とボルダリングです。NFLは今年11月にマイナス気温の屋外で現地観戦してきました。 最近リードクライミングの講習を受けまして、ガシガシと岩を登っております。
さて、今回はAWSアカウントとAWS SSOのお話をしようと思います。 既に社内エンジニアへの共有や社内WikiにAWS SSOの利用マニュアルを残していますが、経緯や変遷について記載していないので、トレタ社員の方にも読み物として読んでいただければなと思っています。
免責事項
本記事を参考に実施したことで発生した金銭・セキュリティ等あらゆる問題について責任を負いかねますので、自己責任のもと実施していただくよう、よろしくお願いいたします。
また、誤り等あればはてブ等でご指摘いただけますと幸いです。
入社直後の状態
トレタはしばらくインフラ担当者がごく少数な時期が続いたこともあり、いろいろ改善しないといけないところがあるな、というのが入社直後の印象でした。 とくにAWSアカウント構成の改善はすぐに取りかかれそうだと思ったので、着手することにしました。 当時の状況はこんな感じです。
- AWSアカウントは2つあり、本番環境用(以降本番アカウント)とステージング用(以降ステージングアカウント)という分け方
- 本番アカウントが親アカウントとなり、ステージングアカウントと一緒に利用料金を支払っている
- 監査ログは本番アカウントで保管されている
- 検証用にリソースを作成する場合はステージングアカウントに作成する
- インフラ担当者がそれぞれのアカウントに社員ごとにIAMユーザを作成し、クレデンシャルを払い出す
図に起こすとこんな感じです
おそらくAWS利用初期の組織はこういった運用をされている企業が多いと思います。 ただ、ある程度規模が大きくなり運用年数も経っていたトレタでは、以下のような問題が起きていました。
- ステージングアカウントで検証用のリソースが放置され、プロダクトとして利用されているのかどうかわからない
- これにより、何人もうかつにAWSリソースを触ることができない
- よって、AWSのオペレーションがインフラ担当者に集中し、権限移譲が難しい状態に陥っていた
- IAMユーザについて、本番アカウントとステージングアカウントで管理上のズレが発生している
- 本番環境と監査ログ保管が同居していることで様々なリスクがある
ちなみに本番アカウントのアカウント名も人の名前になってたりして歴史がありますね笑
とくに「うかつにAWSリソースを触ることができない問題」「本番環境と監査ログ保管の同居」については早急になんとかするべきだと判断し、まずはAWSアカウントをきちんと構造化して、プロダクトが運用されているアカウントに検証用リソースを作らなくてもすむ、監査用のアカウントを作成し監査ログを別にできるような状態にしようと思いました。
AWSアカウントの整理
AWSのマルチアカウントベストプラクティスは、2017年のAWS Summit Tokyoにて「AWS におけるマルチアカウント管理の手法とベストプラクティス」というセッション名でAWSの高田様が登壇されております。
https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf
スライド終盤の「本日のまとめ」 以降がわかりやすくておすすめです。
今回の構造化もこのベストプラクティスに則り、AWS Organizationを利用し以下のアカウントに分けることにしました。
アカウント名 | 内容 |
---|---|
支払い用アカウント | 以下の全ての子アカウントの親として、AWSで発生した料金を支払うアカウント |
本番アカウント | トレタの台帳システムが稼働している本番環境のアカウント |
ステージングアカウント | トレタの台帳システムが稼働しているステージング環境のアカウント |
検証用アカウント | AWSのサービスをお試しで利用したいというときに使うアカウント。消されても基本文句言わない |
監査用アカウント | 各アカウントのCloudTrailログ等監査に関するログを保管するアカウント |
前職でのAWSアカウント運用経験から、将来情シス用のアカウントが必要になるだろうと予想していますが、近い将来に関してはニーズがないと判断し一旦作成対象から外しました。 AWS Organizationを利用すれば、秒でアカウントを作成できるのでそのときに作れば問題ありません。
プロダクトのアカウントに情シスのリソースを作ってしまうと移行がマジで大変なのでみなさん気をつけましょう
アカウント構造化に合わせてアカウント名やメールアドレスもきちんと規則性をもたせるようにし、誰がみても理解できるような状態を目指した結果、以下のようになりました。
これにより、当初望んでいた「プロダクトから隔離された好き勝手触れるAWSアカウント」と「監査用の専用のAWSアカウント」の用意が完了しました。
ここではCloudTrail等のログを中央集権アカウントに集約する設定については割愛します。ググってください
おまけ:支払いアカウント切り替え
今回の構造化に伴い、AWSの支払いアカウントが本番アカウントから支払い用アカウントに変更となりました。 AWSの営業担当の方にアドバイスをいただき、以下の手順に沿って実施しました。
- 支払い用アカウントの作成&AWS Organizationの有効化
- 本番アカウントのAWS Organization解散(このとき、ステージングアカウントに支払い方法を設定する必要があります)
- 支払い用アカウントのAWS Organizationに本番アカウント、ステージングアカウントを招聘、完了
(この情報については記事冒頭の免責事項も合わせてご確認ください)
2実行後〜3実行前まで、AWSアカウント単体で請求が発生するためご注意ください。 私は事前に社内経理担当者に連絡しており、スムーズに作業ができました。
AWS SSOの導入
さて、上述の通りAWSアカウントを細分化することができましたが、各AWSアカウントへのログインに関して問題が見え始めました。 社内のエンジニア全員に検証環境を触ってほしいと言いつつ、検証用アカウント用のIAMユーザを発行する運用負荷やAWSのアカウント切り替え作業など、煩雑な作業がさらに増えてしまいました。 一般的に、「ログイン専用アカウントを用意し、ログイン後にSwitchロールする」という方法が普及しており、今回もその方法を採用しようかと考えていましたが、何かしらのSingle Sign On(SSO)を導入できないかと検討し始めました。
前職ではとあるIDaaSのSSO機能を利用してAWSにログインしており、SSOの管理画面上で各AWSアカウントへのフェデレーションログインを設定することで、容易にAWSマネジメントコンソールにログインできるような環境ができていました。 つまり、「1度SSOのログイン時に認証するだけでSSOのポータル画面から様々なAWSアカウントにクリックするだけでログインできる」という状態です。 現在残念ながら社内にSSOを導入できていないため、こういった状況には至れていません。 欲を言えば上記SSOサービスを利用しAWSだけでなく様々なSaaSへのログインできる状態を望んでいるのですが、せめてAWSアカウントだけはどうにかしたいと考え、AWS SSOを試験導入(後に本採用)することにしました。
現状、社内でActiveDirectoryやLDAPを運用していないため、ミニマムスタートということでAWSのSimpleADを利用してSSOのユーザ管理を行い、利用を開始しました。 設定についてはAWSのドキュメントを参考にして作業した以上のことをやっていないので説明は割愛します。
AWS SSOの設定が完了し、AWS SSOにログインするとOrganizationsに紐づくログイン可能なアカウント一覧が表示され、マネジメントコンソールへのログインや一時クレデンシャルの払い出しをすることができます。 1度AWS SSOにログインすればセッションが切れるまでの間はアカウントの切り替えは容易です。都度IAMユーザログイン時の多要素認証をする必要はありません。
アプリケーションの追加とIAMポリシー
前職で利用していたIDaaSのSSO機能では、「SAML認証するためにAWSにIDプロパイダーを作成し、ログイン後にどのIAMロールにAssumeRoleするか」という項目を設定する必要がありました。 そのため、新しいAWSアカウントを作成すると
- ログイン後に適用するIAMロールを作成する
- SSOにアプリケーションを作成する&SAMLメタデータドキュメントのダウンロードする
- AWSにIDプロパイダーを作成する
- IDプロパイダーにSAMLメタデータドキュメントを登録する
- SSOのアプリケーションにIDプロバイダーおよびIAMロールを設定する
といった作業が必要でした。 例えばOneLoginの設定について、Serverworksさんの以下の記事をご覧いただくとイメージがわくかもしれません。
OneLoginを利用してAWSにSAMLでログインする – サーバーワークスエンジニアブログ http://blog.serverworks.co.jp/tech/2018/06/22/onelogin-aws-saml/
この作業はある程度自動化できるとはいえ、(IDaaS側のAPIが不十分なこともあり)SAMLメタデータドキュメントの交換は自動化できず、ちょっとした運用負荷がありました。 それに対してAWS SSOは、AWS SSO側でSAML認証の設定を自動化できているため、AWS Organizationに新しいAWSアカウントを追加したあとは「どのSSOグループに(どのSSOユーザに)」「どのアクセス権限セットでログイン権限を与えるか」という設定をAWS SSO管理画面上で30秒ほどポチポチするだけでAWS SSOポータル画面からAWSにログインすることができます。
この「アクセス権限セット」というのはいわゆるIAMロールのようなもので、AWS SSO側でIAMポリシーを一括管理しています。 AWS SSOとAWSログインアカウントを紐付ける作業を実施すると、アクセス権限セットに登録されたポリシーを元にAWSログインアカウント側でIAMロールが生成され、IDプロバイダーの生成・紐付けもやってくれます。 細かなリソースの管理は難しいですが(後述)、SSOにログインするユーザのグループをある程度まとめられるならとても便利な機能となっています。
トレタでの現状のログイン先アカウントとアクセス権限セットについては、各職種ごとにグループを作って以下のように分けています。 (やや不正確なところはありますが概ねこのとおりです。)
AWSアカウント | 職種 | 付与権限セット |
---|---|---|
本番アカウント | 正社員インフラ担当 | Admin用権限セット |
本番アカウント | 正社員開発者 | Developer用権限セット |
ステージングアカウント | 正社員インフラ担当 | Admin用権限セット |
ステージングアカウント | 正社員開発者 | Developer用権限セット |
検証用アカウント | 正社員インフラ担当&開発者 | Admin用権限セット |
支払い用(SSO管理用) 監査アカウント |
SREリーダーなど限られた人のみ | Admin用権限セット |
支払い用アカウント | 正社員経理担当 | 支払情報閲覧権限セット |
多要素認証方法の追加(Email → 認証アプリ)
導入当初、AWS SSOはユーザ管理DBにSimpleADを利用するとEmailで認証コードが送られる形式の多要素認証しか選択できませんでした。 ログインするたびにメールの受信箱を確認し番号をコピペするという作業が必要でした。
が、今年11月に入ってから認証アプリ(Google Authenticatorなど)を利用した多要素認証を設定することができることを気づきました。
AWS SSOを使い始めてから切実に願望していた機能のひとつです。 設定の変更はAWS SSO稼働アカウント(要は親アカウント)のマネジメントコンソールにログインし、ボタンポチですぐにできます。
しかも素晴らしいことに、
- 認証アプリを利用しない場合でも多要素認証を強制でき、その場合はメールアドレス宛に認証コードを送信する
- 管理者だけでなくユーザ自身が認証アプリを登録することが可能
という設定が織り込まれています。 新入社員用等に、SSOユーザ作成時はメールアドレスによる認証で設定しておき、本人が望めば認証アプリを自分自身で設定してもらうというルールにしておくことで、SSOユーザも管理者も楽な状態を維持することができました。
awscli v2(preview)がSSOログインに対応
2019年10月後半頃に「awscli v2のインストール方法」について紹介された記事が上がってきました。 このときは「ふーん、Pythonがバンドルされるのか」ぐらいの気持ちでしかなかったのですが、直後に驚きのリリースが発表されました。 そう、awscli v2とAWS SSOの連携です。
それまでは、AWS SSOの画面に表示されるクレデンシャルを ~/.aws/credentials
にコピペするという運用をしており、作業の手間とプロファイル名書き換え等による事故のリスクを抱えた状態で運用していました。
できるだけ事故を減らすために
~/.aws/config
で role_arn と source_profile を使うやや黒魔術的な取り組みをしてたりしました。 説明がめんどくさいので、気になる方は勉強会等で捕まえていただければお話します。
実際にawscli v2とAWS SSOの連携機能を使ってみて利便性は格段に向上しました。
イメージをお伝えすると firebase login:ci
とほぼ同等のことを実現しています。
手元のコンソールで aws2 sso login --profile [プロファイル名]
と打つことでブラウザの認可画面に遷移し、許可ボタンを押すとSSOのアクセストークンが発行され、そのアクセストークンを使ってフェデレーションログインを実現しています。
しかし、普段よく利用するAWS操作系のツール(Terraformやeksctlなど)が残念ながらSSO用のプロファイル設定に対応していないため、引き続きAWS SSOの画面から一時クレデンシャルをコピペする作業が必要となります。
AWS Organization外のAWSアカウントをAWS SSOへ参画させる
株式会社トレタはトレタCC株式会社(以降トレタCC)という子会社をもち、トレタCCのサービス展開にもAWSを利用しています。 しかしながら、会計上の理由によってトレタCCのAWSアカウントを株式会社トレタが管理しているAWS Organizationには所属していません。 そのため、トレタCCにログインする必要のある社員にのみIAMユーザを発行しているという状況です。 ですが、トレタアカウントとトレタCCアカウントの両方を行き来する社員も存在するため、可能な限りログインの窓口を1つに絞りたいと考えています。 この状況は多くの会社に当てはまるのではないでしょうか。
AWS SSOでは、Organizationに紐付いたAWSアカウントだけでなく、Organization外のAWSアカウントにフェデレーションログインすることも可能のようです。 SAML ProviderやSAMLメタデータアップロードなど、通常のSAML連携の設定を実施すれば連携可能だと思われます。 (本当は設定済みのものをお見せしたかったのですが、現在トレタCCのアカウントとAWS SSOの連携は実施していません。社のポリシーや法務・経理周りの許可がおり次第実施する予定です。)
AWSタグを利用した社外協力者への限定的な権限付与
AWS IAMでは、これまで多くの利用者に利用されてきたRBAC(ロールベースアクセス制御)だけでなく、ABAC(属性ベースアクセス制御)を提唱しはじめました。 これは、今まで「ロールやユーザごとにポリシーをわける制御」であったのが、「ユーザやロールで同じポリシーを共有し、IAMとリソースに付与されたタグ(属性)の一致をもって制御する」という方式です。 ABACを実現するには、各ロールやユーザにタグを付与するか、re:Invent2019直前に発表されたSession Tagsを利用する必要があります。
RBAC、ABACやSession Tagsの説明はクラスメソッドさんのブログに詳しく記載されていますので、そちらをご参照ください。
[UPDATE]フェデレーションでタグを渡せるSTSの新機能Session Tagがリリースされました #reinvent | Developers.IO
https://dev.classmethod.jp/cloud/aws/session-tag-on-id-federation/
ただ、残念ながらAWS SSOでABACを実現することは難しいです。 何故ならば
- アクセス権限セットによって作成されるIAMロールにタグを付与することが現状できない
- SessionTagsを利用するためのSAMLアサーションの属性情報を設定できない
という状況のためです。 AWSアカウントが少なければ、自動生成されるIAMロールを追従してタグを付与することでABACを実現できますが、AWSアカウントやアクセス権限セットの組み合わせが多くなるととてもじゃないけど運用が回りません。
「おそらく近い将来AWS SSOのSession Tagsサポートがリリースされるだろう」という予想のもと、一旦リソースに特定のタグを付与することで「ABACっぽい記述のRBAC」を実現しました。 モデルとして「トレタNowチーム担当の業務委託にSSM Session Managerを特定のEC2にのみ実行可能」を考えます。
今回は SsoPermissionForContractEngineers:toreta-now
というタグを対象のEC2インスタンスに付与し、アクセス権限セットのポリシーの一部(ステートメント)を以下のように設定しました。
{ "Effect": "Allow", "Action": [ "ssm:StartSession", "ssm:TerminateSession" ], "Resource": "*", "Condition": { "StringEquals": { "aws:ResourceTag/SsoPermissionForContractEngineers": "toreta-now" } } }
これにより、SsoPermissionForContractEngineers:toreta-now
が付与されたEC2インスタンスにはSession Managerでログインでき、そうでないインスタンスにはログインできないことを確認しました。
現状まだ実務での利用に至れていませんが、対象のリソースにこのタグを付与したり許可アクションを設定できれば、実運用を始めようと考えています。
(Session Tags対応がリリースされれば、ステートメントの toreta-now
を ${aws:PrincipalTag/SsoPermissionForContractEngineers}
に置き換えることで同様のことができると思われます。)
この検証で思い当たる点、気をつける点についてわかったことがあるので以下にまとめます。
まずリソース側のタグ管理は、できるだけコードベース管理されていることが望ましいです。 最近だとTerraformやCloudFormationを利用してリソース管理をされている方が多いと思いますが、ABACを実運用する上で必要になると感じました。
また、ポリシーのステートメント文内で利用する条件キーが、AWSサービスによって異なる点に気をつけてください。
例えば、同じEC2にアタッチしているタグであったとしても、ssm:StartSession
が aws:ResourceTag
であるのに対し、 ec2:StartInstances
は ec2:ResourceTag
だったりします。
各アクションと条件キーの対比については、以下のページに各サービスごとにまとまっていますので、ポリシーを作成するときに参考にしてください。
AWS のサービスのアクション、リソース、および条件キー AWS Identity and Access Management
とくにS3の条件キーはかなり複雑で、s3:GetObject
の場合は s3:ExistingObjectTag
条件キーが必要で、s3:PutObject
の場合は s3:RequestObjectTag
条件キーが必要になります。
この s3:RequestObjectTag
条件キーがなかなか厄介で、この条件に合致した場合アカウント内のあらゆるS3バケットにPutObjectできてしまうということを観測しました。
そのため、どうしてもポリシー側でリソース名を記述必要があると判断し、一旦PutObjectを否認するようにしています。
どうしても必要な場合は sts:AssumeRole
で専用ロールになってから作業するという逃げ道を考えています。
考察と今後の展望
以上、AWS SSOを導入したお話について執筆しました。 とくにAWS SSOを導入するべきだと思われる状況について私見を述べます。
- AWSへログインする人が20名を超えている
- 管理しているAWSアカウントが複数(3以上)あり、それらは1つのAWS Organizationにまとめられる
- それらのアカウントにログインする役割の人が3種類以上(例:AWS管理者、社員エンジニア、業務委託エンジニア)
- OneLoginやOktaといったIDaaSのSSO機能を導入していない
これに当てはまる組織に対しては大きな運用負荷軽減効果を望むことができますので、ぜひAWS SSOをご検討されてはいかがでしょうか? とくに「AWSアカウントが5以上あり、ログイン用アカウントからSwitchロールして目的のアカウントにログインしている」という組織の方にはおすすめしたいです。
また、すでにIDaaSを導入されている組織におきましても、AWSアカウントを非常に多く管理されている場合(目安として10以上)、AWS SSOを利用することでコネクター設定の作業負荷が軽減できるかもしれません。 私の経験としても、前職で利用していたIDaaSよりAWS SSOの設定作業が非常に楽だと感じました。 AWSのみAWS SSOで他はIDaaSのSSO、といった使い分けをすることも視野に入れておけばよかった、という気持ちもあります。 AWS SSOでも既に設定されているActive Directoryと連携することができるため、ぜひ検証してみてください。
ところで、本記事を執筆中にFinatextさんが興味深いアドベントカレンダーを公開していました
FinatextにおけるAWSのガードレール戦略の紹介 - Finatext - Medium
https://medium.com/finatext/finatext-aws-guardrail-2705cd1e3679
この記事を拝見させていただき、すぐに「これはAWS SSOを導入したら相当楽になるはず!」と直感しました。 ぜひご検討いただけますと幸いです笑(と言いつつ免責事項をご確認の上、きちんとご調査いただきますようよろしくお願いいたします。)
逆に、「AWS OrganizationのSCPを導入した」ことについては、 その機能があったことを完全に失念しており はっとさせられました。
アカウントレベルで制限したいアクションをアクセス権限セットで封じるのはかなりめんどくさかったので、大変参考になりました。後日設定してみます。
これとABACを組み合わせることでいい感じのアクセス権限払い出しができそうな気がしています。
ここまでAWS SSOのポジティブな話を記載してきましたが、もちろん問題もあります。
まず、ひとつのAWS OrganizationにひとつしかAWS SSOを設定できません。 至極真っ当な仕様であるとは思いますが、これによりAWS SSOの検証・実験のハードルが高いことが問題点であると感じました。 完全に独立したアカウントを用意すれば検証は可能ですが、稟議・経費精算といったワークフロー上の手間が増えることになります。
もうひとつは、前述の通りABACが現状難しいことと、アクセス権限セットのポリシーをコードベース管理できないことです。 前者はおそらくそのうちリリースされるとして、後者は管理のためにAPIの提供を望みます。
また、現場のエンジニアが片手間でSSOを設定することは負担が大きく、せめてユーザ管理をActiveDirectoryやLDAP等を利用して情シス側に移管できればと思っています(何卒宜しくお願いします)。
最後にアドバイスとして、組織の運用を大きく変えるような仕組みを導入したいときは「まず自分を生贄に捧げる」という覚悟を持って取り組むと、それを運用し始めたときの利点欠点の理解が進みます。 私の場合、それまで使っていたIAMユーザを捨ててすべてAWS SSOに寄せることで良い点・悪い点を実感として得ることができ、これらを同僚に共有することで本当に導入すべきかどうかをきちんと議論できたと思います。 また、良い点ばかりに目を向けていると導入後に困難な事象に遭遇した場合に不幸を生む可能性があるので、「きちんと悪い面にも目を向ける」「どうしてもやめたくなったらどうするか」ということをきちんと考えて、共有しておけば、自分がいなくなったとしても
終わりに
この記事が投稿される頃には Bears @ Packers が終わっているはずで、その試合の結果次第では地区優勝に大きく近づきます。
Packers勝利&Rams敗北でプレーオフが確定しました!残り2戦のうち1勝すれば地区優勝です。
ただ、プレーオフに向けて不安要素がかなり多い(とくにラン守備とフリーになれないWR陣)ですが、1発勝負ぜひ勝ってスーパーボウルに行けたらと思ってます。
(でもWeek12でボコボコにされた49ersと飛び道具テイサム・ヒル擁するセインツには勝てる気がしない)
Go Pack Go!