Developers.IO Cafe でのAWSアカウントとステージの構成
渡辺です。
Developers.IO Cafe のドキュメントシリーズ第4弾は、AWSの環境周り、つまりAWSアカウントの構成について解説します。
ステージ毎にAWSアカウントを分ける
カフェでは、プロダクション環境(PRD)、ステージング環境(STG)、インテグレーション環境(ITG)、開発環境(DEV)のステージ(環境)を持ちます。 原則としては、 このように プロダクトをステージに分ける場合、AWSアカウントを分割する ことがセオリーです。
カフェではさらにIoTアカウントを作成しています(後述)。
AWSアカウントを分割した場合のメリットは多くあります。
各環境でアクセスポリシーが明確になる
例えばIAMでログイン可能なユーザを明確にすることができます。 他の環境へのアクセスは許可しなければできません。 間違えてプロダクションを操作といった誤操作を防止できます。
リソースが混在しない
カフェは、SaaSとしてシステムを提供することを目標としています。 このため、リソースもかなり多く、各ステージ毎のリソースが同じAWSアカウントに混在するのは危険です。
コストを分けやすい
AWS環境が別れれば、コスト分析も簡単です。 同一AWS環境でも不可能ではありませんが、手間が違います。
デメリットも幾つかあります。
作るのが面倒くさい
アカウント発行は手間ですが、ウチの会社はAWSで食っているので・・・(笑)
共有リソースを使いにくい
仕方なく各ステージをひとつのAWS環境で使うケースのひとつがVPN接続です。 VPCやVPNが絡んでくると、AWSアカウントを分割することで、必要以上のコストがかかり、断念することがあります。 カフェはサーバレスアーキテクチャで、VPNなどとも無縁なため、発生しません。
CloudFormationによる環境構築
AWSアカウントやステージが増えた場合に問題となるのが、環境構築です。 IAM Role、DynamoDBテーブル、StepFunction、S3バケットといったリソースを手動で作ったら、確実にミスを犯します。 このため、原則としてすべてのリソースはCloudFormationで定義する方針となります。
例外となるリソースとしては、Route53等ドメイン周りのリソースです。 SSL証明書の発行やドメイン設定などはCloudFormationで行うのは辛く、一度設定すれば二度と変更も無いため、手動で行っています。
AWSアカウントを作成し、CloudFormationを流せば、新しい開発環境を簡単に構築できます。
IoT関連リソースはステージに紐付くべきか?
カフェのシステムでは、IoTデバイスと接続し、重量データや位置データをAWSに送信しています。
ある重量センサーがあった時、そのセンサーはどのステージにデータを投げるのでしょうか?
結論としては、センサー(物理)はステージを意識しない構成がベターです。
ステージ毎に証明書を切り替えるのが辛い
あるデバイスが、 PRD環境とSTG環境のどちらにもデータを送信できる のが理想です。 この時、PRD環境とSTG環境で、それぞれ証明書を作る必要があります。
それぞれの証明書をデバイスにインストールし、送信先AWSアカウント(トピック)の設定も行い、それを切り替える機能が必要です。
デバイス(物理)でやるのは辛いです。 Greengrassを利用するといった手段も考えられますが、Greengrassの環境がステージ毎に別れていては意味がありません。
モノはモノ、クラウドはクラウド
デバイスにインストールする証明書はひとつにし、送信先のAWSアカウントも変更したくない。 かつ、データ送信先のステージを切り替えたい。 でも、AWSアカウントはステージ毎に分割したい・・・。
それらを考慮すると、 IoTデバイスでデータを送信する専用のAWSアカウントを作成する ことがベターとなります。 結局、モノはモノとしてデータを投げる先は固定である方が自然なのです。
なお、VPN問題もこのパターンで解決する場合があります。 VPN専用AWSアカウントを作成し、各ステージを持つAWSアカウントのVPCとVPC Peeringする構成です。
IoT ActionsでクロスアカウントでLambdaを実行する
IoTデータはトピックに投げられた後、IoT ActionsでLambdaに渡されて処理されます。 ぱっと見、ドキュメントもありませんし、IoTの設定画面からはできませんが、設定自体はLambdaはARNで指定します。
クロスアカウントでいけそう。
確認した所、 実行されるLambdaに適切なポリシーを与えれば、クロスアカウントでIoT Actionを実行出来ました 。 これで、IoT Actionを介して、各ステージのAWS環境にデータを送信することが実現出来ます。 送信先ステージを変更する場合は、IoT Actionの設定を変更するだけなので、物理デバイスには一切の変更は不要です。
Lambdaアカウント(yyyyyyyyyyyy)側
SensorLambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: sensor_xxx Action: lambda:InvokeFunction Principal: iot.amazonaws.com SourceAccount: "XXXXXXXXXXXXXXXX" SourceArn: !Sub arn:aws:iot:${AWS::Region}:XXXXXXXXXXXXXXXX:rule/action_name
IoTアカウント(XXXXXXXXXXXXXXXX)側
Rule: Type: AWS::IoT::TopicRule Properties: RuleName: sensor_xxx TopicRulePayload: Sql:SELECT * FROM 'sensor_xxx' Actions: - Lambda: FunctionArn: !Sub arn:aws:lambda:${AWS::Region}:yyyyyyyyyyyy:function:sensor_xxx
まとめ
AWSアカウントはステージ毎に作成しています。 各ステージのリソースは原則としてCloudFormationで管理しています。
ただし、IoTデバイスと接続する専用のAWSアカウントがあります。 センサーからのデータは、このAWSアカウントをGatewayとして、設定されたステージのAWSアカウントに送られます。