TECH PLAY

電通総研

電通総研 の技術ブログ

822

こんにちは!X イノベーション 本部  エンタープライズ XRセンターの加納です。 この記事は 電通国際情報サービス Advent Calendar 2022 の15日目の記事です。 もうすぐクリスマスですが、プレゼントの用意は出来ていますか?まだですか?まだですよね? そんな方のために大貫サンタさんが靴下から取り出したのは… HMD です! 「 HMD 」という単語にピンとくる方は少数派かもしれません。 HMD とはHead-Mount-Displayの略で、つまりは VR 体験をする際に頭に被る、アレのことです。 加納と大貫サンタは3D・ VR 関係の部署に在籍しているため、今日はそんな部署ならではの機材を紹介していこうと思います。 個人で使用されているものだけではなく、事業者向けによく使用される機種も比較に入れてご紹介いたします。 比較していく機種は以下です。 Meta Quest2 Meta Quest Pro VIVE Pro2 Varjo Aero Varjo XR-3 以上の5機種が今回被り比べの対象となります。 性能面ではさまざまな記事が出ていますので、この記事での主な比較点は 重さ サイズ 価格、入手難易度 メガネを装着したまま被れるか? を重視して被り比べをしていきたいと思います。ではいきましょう! Meta Quest2 Meta Quest Pro Vive Pro2 Varjo Aero Varjo XR-3 メガネとHMD 被りやすさ4位タイ 被りやすさ3位 被りやすさ2位 被りやすさ1位 まとめ Meta Quest2 世界で最も普及している HMD と言ったらコレなのではないでしょうか。上の画像ではデフォルトのゴムバンドをEliteストラップに付け替えています。 スタンドアローン ・外付けセンサー不要で稼働し、被った状態で外部を確認することもできます(白黒画像)。 スタンドアローン ではありますがPCに接続して動かすこともでき、Steamのゲームもプレイできます。 デフォルトのゴムバンド装着での重さは 529g (参考値) Eliteストラップ装着での重さは 650g (参考値) と、非常に軽量なのが特徴です。 被ってみるとこんな感じです。 大貫サンタ「いつものって感じ」 ExRCではメンバー全員がQuest2を所有しているため、被るとあーこれだこれーと思ってしまうんですよね。一番 稼働率 の高い HMD です。 お値段は 59,400円 (2022年12月現在/公式価格)とお求めになりやすい価格、かつ家電量販店でも販売しており入手難易度も低いため、クリスマスプレゼントの第一候補になるのではないでしょうか。 Meta Quest Pro 去る2022年10月に発売された HMD で、上に出てきたMeta Quest2の上位機種です。 重さは 718g (参考値) 似たような形状のEliteストラップ装着時から比較しても70g程度の増量ですが、被った感じはいかがでしょう? 大貫サンタ「前が薄い!帽子のままでも被りやすい!あとQuest2より軽く感じる。前後のバランスがいいのかな」 Quest Proでは、Quest2にあった頭頂部をおさえるゴムバンドがなくなったことで格段に被りやすくなりました。髪型も崩れにくくなってありがたいですね。 スタンドアローン ・外付けセンサー不要・PC接続可能なのは同じですが、外部確認カメラがカラーになったのが大きな変化です。これによりAR(拡張現実)的な使い方がしやすくなりました。 加えてアイト ラッキング (視点を読み取る)・フェイスト ラッキング (表情を読み取る)などが搭載され、できることの幅が広がりました。 顔と画面の隙間は広めで、隙間からは外の光が入ってきます。オプションパーツで埋めることも出来ますが、パススルーの精度が高く外部が鮮明に見えるためかARゴーグルのような感覚があり、個人的には開いたままでいいなあという印象です。 お値段は 226 ,800円 (2022年12月現在/公式価格)とお高め。ですが装着感もできることも大幅に変わっているため、高すぎ!といった印象はありません。 まだ家電量販店で現物を手に取ることは出来ませんが、Metaの公式通販から購入できるため入手難易度は低め。クリスマスに間に合うかは…お住いの地域次第かな?といったところです。 Vive Pro2 VR の先駆者、HTC Viveの上位製品です。Meta Quest(当時はOculus Quest)が登場するまでは、 VR といったらVive!という感じでしたね。Pro2は耳に可動式のヘッドホンがついているのが特徴的なデザインです。 重さは 846g (参考値/コードが机についた状態) Vive Pro2はPC接続で稼働し、稼働には外付けセンサー( ベースステーション )を必要とします。 大貫サンタ「Meta系と比べるとかなり大きく感じる。でも重さに偏りがなくて安定してる」 外付けセンサーと言うと煩雑な感じがするかもしれませんが、フルト ラッキング をしたい場合にはVive公式でトラッカーが別売りされていますので、外付けセンサーありの製品を選択するのがおすすめです。 お値段は 178,990円 (2022年12月現在/フルキット/公式価格)でセンサー( ベースステーション 2.0)が2台同梱されています。 家電量販店で見ることは少ないですが、公式通販で入手が可能です。クリスマスに間に合うかは…Meta Quest Proと同じく、お住いの地域次第でしょうか。 Varjo Aero フィンランド に本社を構えるVarjoの製品です。ここからは エンタープライズ 色が濃くなってくるため、個人で持っている方がぐっと減るのではないでしょうか。 重さは 720g (参考値/コードが机についた状態) と、Meta Quest Proとおよそ同じくらいの重さです。 こちらもPC接続で稼働し、稼働には外付けセンサーを必要とします。 大貫サンタ「前に重心がある感じ、でも全体がそんなに重くないから大丈夫」 Varjo Aeroは軽量ながらVive Pro2よりも表示解像度が高いです。解像度が高いだけではなく、中心に向かって27PPD~35PPD(PPD…1度あたりの ピクセル 数)へと解像度が高くなっていきます。 Varjo製品は自動でPD(瞳孔間距離)を調整してくれます。これにより鮮明に映像が見えるほか、 VR酔い もしにくくなります。 お値段は 316,800円 (2022年12月現在/公式価格)とお高め。ですがこの解像度を味わうと他の VR にはなかなか戻れないかもしれませんね。 注意していただきたいのが、Varjo Aeroは紹介する5機種のうち唯一外部確認(パススルー表示)ができないタイプの HMD だということです。解像度は高いですが、用途を十分に確認した上で検討してみてください。 家電量販店では見かけないですが、公式通販で購入が可能です。ただし後述のVarjo XR-3と同じく外部センサーの入手がしづらいため、トータルでの入手難易度はちょっと高めです。 Varjo XR-3 こちらもVarjo社の製品で、紹介する中では最もハイエンドな機種になります。 重さは 1008g (参考値/コードが机についた状態) 堂々の1㎏超え。見えますか、ごっつい排気口がきらめいているのを。XR-3は作動するとかなりの熱を持ちます。 大貫サンタ「ずしっと来る。圧倒的に重い…けど画質も圧倒的にいい」 外部確認できるカメラの精度が高く、一度被るとついつい外さずにカメラであれこれ済ませてしまいがちですが、これだけ重いものを長時間被っていると首が筋肉痛になりますので気を付けましょう。 Aeroは解像度が徐々に高くなる構造でしたが、XR-3は視野の中心にあたる部分に別のディスプレイを搭載しており、中心部は71PPDを誇ります。 なお視力2.0の人の目は、60PPDを超えると ピクセル を見分けることが出来なくなるそうです。ですのでXR-3は人間の目の解像度を超えた HMD であるといえます。とんでもないですね。 こちらもPC接続で稼働し、外付けセンサーがなくても稼働しますが精度を高めるためにはセンサーが必要です。 問題の入手難易度についてですが…XR-3は エンタープライズ 用途が主であるため 一般での販売はされていません 。また昨今の円安や 半導体 不足もあり、価格もはっきり示すことが出来ません。 だいたいコンパクトカーと同じくらいの値段 だと思っておいていただけると良いかと思います。恐ろしいですね。 Varjo Aeroの項目でも出てきたセンサー( ベースステーション )についてですが、現在単体での入手が困難となっています。ですのでセンサーを同梱しないがセンサーを必要とするタイプの HMD を購入される際には、Vive Pro2などHTC製品のフルキットを購入し ベースステーション を入手する必要があります。これも入手難易度を上げる一因となっています。 ExRC に問い合わせていただけたらまるごとご相談に乗れるんですけどね!(宣伝です!) メガネと HMD ここからは横道にそれて、メガネ使用者に優しい HMD はどれなのか?を紹介させていただけたらと思います。 ※完全に主観です。個人差やメガネの形状によって変わるものですので、参考程度にご覧ください。 被りやすさ4位タイ Varjo Aero&Varjo XR-3 ストラップの構造なのでしょうか?装着した後は楽なのですが、装着するのが割と大変です。 具体的に言うと、こうやって後ろから装着するとメガネがあたってしまうので、 前側を先に被る必要があります。メガネをはめ込むような感じです。 コツが必要であることと、かぶった後の位置修正のしにくさから、ちょっとメガネに優しくない HMD だなと判定させていただきました。 被りやすさ3位 Meta Quest2 Meta Quest2にはメガネ装着用アタッチメントが付属しています。 左右の差が分かるでしょうか? 左がアタッチメントを装着したQuest2です。 ばらしてみるとこんな感じで、顔にあたる部分と本体の間に噛ませるパーツがあるのです。 なので正直メガネでも快適に装着できるのですが、全体的に小ぶりなので大きめのメガネはちょっとひっかかります。ということで3位にさせていただきました。 被りやすさ2位 Vive Pro2 こちらはメガネが入る内部のスペースが大きいです。クッションが柔らかくメガネのつるが圧迫されないため、痛くなりません。 クッションの柔らかさが伝わるでしょうか? ※メガネのつるが歪んでいるのは元からです。踏みました。 被りやすさ1位 Meta Quest Pro Meta Quest Proは顔と画面の隙間が大きく、また主におでこで HMD を固定するのでメガネに干渉する部分がほとんどありません。 指さしているところをくるくる回すことで画面と顔の距離を離すことができ、鼻当てが押さえつけられることもなく快適に使用できます。ですが、光を遮断するパーツを付けるとまた変わると思います。 まとめ 今回紹介した内容を総括した図はこのようになります。 なお価格面、有線無線等は使用状況によって優劣が変わるため順位付けは行っていません。 また繰り返しになりますがメガネとの相性は個人差がありますので、あくまで筆者の場合と思っていただけると幸いです。 個人的にはメガネユーザーとしてMeta Quest Proが好みで、大貫サンタは持ち運びやすさからMeta Quest2が好みだとのことです。 どんどん新しい製品が出てくる HMD 。ARグラスの噂も色々気になるものがありますね。 新しい製品は積極的に触って調べて、お客様に適した機材やソリューションを紹介できるよう、頑張らなきゃな!と思いを新たにしたサンタたちでした。 執筆: @kano.nanami 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。これは 電通国際情報サービス Advent Calendar 2022 12/14の記事です。 プログラミング言語 で クラウド インフラをIaC化できるライブラリとして、 AWS Cloud Development Kit (CDK) が使われることが増えています。CDKではリソースのデフォルト値が設定され、便利に短く記述できる一方で、デフォルト値が必ずしも推奨されるセキュリティ構成になっていない場合があります。 Security Hubのセキュリティ基準 を利用していると、リソースをデプロイした後にアラートに気付いて修正をすることもあるのではないでしょうか。 そこでこの記事では、Security Hubのセキュリティ基準でアラートを出さないためのCDKによるリソースの記述方法を、主要なサービスの種類ごとにまとめました。CDKでリソースを作成するときに、どのような設定を気にした方が良いのか、Security Hubアラートとの マッピング として使っていただけると幸いです。 なお、矛盾しているように聞こえるかもしれませんが、Security Hubのチェックルールは 全てクリアすること自体を目的とするものではない と考えています。 AWS も全てのルールをクリアすることを期待していないでしょう。例えばS3 バケット については、 アクセスログ を出力するようにチェックするルールがありますが(S3.9)、 アクセスログ を格納する バケット の アクセスログ は出力しないため、全くアラートが上がらない状態にはできませんね。闇雲に全てのSecurity Hubアラートをクリアしようとするのではなく、 アラートからリスクを評価し、対応するかどうかを総合的に判断する プロセスが必要です。「知らずに設定していなかった」ではなく、「知った上で設定するかどうか判断する」状態にするために、Security Hubを活用するのが良いと思います。 おことわり セキュリティ基準として、記事執筆時点の AWS Foundational Security Best Practices を対象とします AWS Foundational Security Best Practices では、30以上の AWS サービスについてのコン トロール (チェックルール)がありますが、この記事ではよく使われるサービスで、CDKで作成することが多いと思われる13種のサービスのみを取り上げます 全てのコン トロール を網羅していません。CDKのデフォルト設定で対応できていないコン トロール を中心に扱います。また可用性に関わるコン トロール や、要件に応じて特別な構成が必要なコン トロール は除外しているものがあります 設定自体の意味、設定することによる影響は割愛しているため、公式ドキュメントなどでご確認ください 設定することによって追加でかかる費用については、記事内では言及していません 記載しているコードは実装方法の一つの例であり、他にも実装方法がある場合があります コード例は分かりやすさのため、関連する最小限のリソースプロパティのみ記載しています CDKで対応できる範囲、かつSecurity Hubのセキュリティ基準の範囲のセキュリティ対策であるため、当然ながらこれらの設定だけをすれば他にセキュリティ対策が不要というわけではありません CDK v2.50.0 で検証しています。今後のアップデートにより実装方法が変更になったり、デフォルトの挙動が変わる可能性があります。 AWS ドキュメントでは一部不自然な日本語訳があるため、わかりやすさのため独自の日本語訳にしているコン トロール があります。 おことわり VPC EC2.2 EC2.6 EC2.18、EC2.19 ELB ELB.4 ELB.5 ELB.6 CloudFront CloudFront.1 CloudFront.2 CloudFront.3 CloudFront.4 CloudFront.5 CloudFront.6 CloudFront.7、CloudFront.8 EC2 EC2.3 EC2.8 SSM.1 ECS ECS.5 ECS.12 ECR ECR.1 ECR.2 ECR.3 RDS RDS.3 RDS.7、RDS.8 RDS.9 RDS.10、RDS.12 RDS.11 RDS.13 RDS.14 RDS.23 RDS.24、RDS.25 DynamoDB DynamoDB.2 S3 S3.4 S3.5 S3.8 S3.9 S3.13 EFS EFS.1 SNS SNS.1 SNS.2 SQS SQS.1 API Gateway APIGateway.1 APIGateway.4 APIGateway.5 VPC EC2.2 英語タイトル:The VPC default security group should not allow inbound and outbound traffic 日本語訳: VPC のデフォルトのセキュリティグループでは、インバウンド トラフィック とアウトバウンド トラフィック を許可しないようにする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-2 (2023/6/27更新). CDK v2.78.0より、 Vpc で restrictDefaultSecurityGroup プロパティが利用できるようになったため、対応が簡単になりました。 new Vpc ( this , "Vpc" , { restrictDefaultSecurityGroup: true , } ); ======以下は過去の対応方法です。====== CDKでは簡単にデフォルトのセキュリティグループのルールを変更できないため、現時点では この投稿 の通り、カスタムリソースを利用してルールを削除することになります。 まずは Vpc を継承した BaseVpc というクラスを作り(名前自由)、セキュリティグループのルールを削除するカスタムリソースを含めます。 コードを表示 import { Stack } from "aws-cdk-lib" ; import { CfnVPC , Vpc , VpcProps } from "aws-cdk-lib/aws-ec2" ; import { AwsCustomResource , AwsCustomResourcePolicy , PhysicalResourceId } from "aws-cdk-lib/custom-resources" ; import { Construct } from "constructs" ; export class BaseVpc extends Vpc { constructor( scope: Construct , id: string , props: VpcProps ) { super( scope , id , props ); const cfnVpc = this .node.defaultChild as CfnVPC ; const stack = Stack. of( this ); const ingressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , UserIdGroupPairs: [ { GroupId: cfnVpc.attrDefaultSecurityGroup , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupIngress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupIngress" , parameters: ingressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-ingress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupIngress" , parameters: ingressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); const egressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , IpRanges: [ { CidrIp: "0.0.0.0/0" , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupEgress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupEgress" , parameters: egressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-egress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupEgress" , parameters: egressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); } } それを Vpc の代わりに利用するだけです。 new BaseVpc ( this , "Vpc" , {} ); ======過去の対応方法ここまで====== EC2.6 英語タイトル: VPC flow logging should be enabled in all VPCs 日本語訳:すべての VPC で VPC フローログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-6 VPCフローログ を有効にします。以下の例ではS3 バケット に出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const vpc = new ec2.Vpc ( this , "Vpc" , {} ); new ec2.FlowLog ( this , "VpcFlowLog" , { resourceType: ec2.FlowLogResourceType.fromVpc ( vpc ), destination: ec2.FlowLogDestination.toS3 ( logBucket , "vpc/" ), trafficType: ec2.FlowLogTrafficType.ALL , } ); EC2.18、EC2.19 英語タイトル:[EC2.18] Security groups should only allow unrestricted incoming traffic for authorized ports 日本語訳:セキュリティグループは、許可されたポートのみに対して制限されていない着信 トラフィック を許可してください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-18 英語タイトル:[EC2.19] Security groups should not allow unrestricted access to ports with high risk 日本語訳:セキュリティグループは、リスクの高いポートへの無制限アクセスを許可してはいけません https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-19 この2つは関連するコン トロール であり、チェック対象となるポート番号だけが異なるので一緒に扱います。 セキュリティグループにHTTP(80)、 HTTPS (443)以外のポートへのインバウンドルールを追加する時は無制限アクセス(0.0.0.0/0)を許可するのではなく、送信元 IPアドレス か特定のセキュリティグループに制限します。 const sshSecurityGroup = new ec2.SecurityGroup ( this , "SecurityGroup" , { vpc , } ); const anotherSecurityGroup = new ec2.SecurityGroup ( this , "AnotherSecurityGroup" , { vpc , } ); // 許可するIPアドレスレンジを制限する sshSecurityGroup.addIngressRule ( ec2.Peer.ipv4 ( "xx.xx.xx.xx/32" ), ec2.Port.tcp ( 22 )); // 別のセキュリティグループに制限する sshSecurityGroup.addIngressRule ( anotherSecurityGroup , ec2.Port.tcp ( 22 )); ELB ELB.4 英語タイトル:Application load balancers should be configured to drop HTTP headers 日本語訳:Application Load Balancer は、HTTP ヘッダーを削除するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-4 dropInvalidHeaderFields プロパティ(CDK v2.47.0~)を利用し、 無効なHTTPヘッダーの削除設定 を有効にします。 new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , dropInvalidHeaderFields: true , } ); ELB.5 英語タイトル:Application and Classic Load Balancers logging should be enabled 日本語訳:Application Load Balancer および Classic Load Balancer のログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-5 ロードバランサーのアクセスログ をS3 バケット に保存します。以下の例はALBの場合です。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , } ); alb.logAccessLogs ( logBucket , "alb" ); ELB.6 英語タイトル:Application Load Balancer deletion protection should be enabled 日本語訳:Application Load Balancer で削除保護を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-6 deletionProtection プロパティを利用し、 削除保護 を有効にします。 const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , deletionProtection: true , } ); CloudFront CloudFront.1 英語タイトル:CloudFront distributions should have a default root object configured 日本語訳:CloudFront ディストリビューション では、デフォルトのルートオブジェクトが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-1 以下の例はS3 バケット がオリジンの場合です。あらかじめ ルートオブジェクト をアップロードした上で、 defaultRootObject プロパティでオブジェクトパスを指定します。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , defaultRootObject: "index.html" , } ); CloudFront.2 英語タイトル:CloudFront distributions should have origin access identity enabled 日本語訳:CloudFront ディストリビューション では、オリジンアクセス アイデンティティ を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-2 CDKではCloudFront ディストリビューション のオリジンをS3 バケット に指定するだけで、 OAI が自動的に設定され、特別な実装は必要ありません。 なお、OAIに代わる OAC については、記事執筆時点では CDKのL2コンストラクトでは未対応 です。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , } ); CloudFront.3 英語タイトル:CloudFront distributions should require encryption in transit 日本語訳:CloudFront ディストリビューション では、転送中に暗号化が必要となります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-3 viewerProtocolPolicy を REDIRECT_TO_HTTPS もしくは HTTPS_ONLY にすることで対応できます。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS , } , } ); CloudFront.4 英語タイトル:CloudFront distributions should have origin failover configured 日本語訳:CloudFront ディストリビューション では、オリジンフェイルオーバーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-4 フェイルオーバー 用のオリジンを別途作成し、 OriginGroup で primaryOrigin と fallbackOrigin を設定します。(「フェイルオーバー」と「フェイルバック」の用語が統一されていませんが、同じものを指していると考えて良いでしょう) const fallbackBucket = new s3.Bucket ( this , "FallbackBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.OriginGroup ( { primaryOrigin: new cloudfrontOrigins.S3Origin ( originBucket ), fallbackOrigin: new cloudfrontOrigins.S3Origin ( fallbackBucket ), } ), } , } ); CloudFront.5 英語タイトル:CloudFront distributions should have logging enabled 日本語訳:CloudFront ディストリビューション では、ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-5 logBucket と logFilePrefix プロパティを指定し、 CloudFrontのログ を出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , logBucket: logBucket , logFilePrefix: "cloudfront/" , } ); CloudFront.6 英語タイトル:CloudFront distributions should have AWS WAF enabled 日本語訳:CloudFront ディストリビューション では、 AWS WAF を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-6 AWS WAFのWeb ACL を作成し、CloudFront ディストリビューション に関連付けます。 コードを表示 const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAclCloudFront" , { defaultAction: { allow: {} } , // scopeは CLOUDFRONT とする scope: "CLOUDFRONT" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "WafV2WebAclCloudFront" , } , rules: [ // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ { name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , webAclId: wafWebAcl.attrArn , } ); CloudFront.7、CloudFront.8 英語タイトル:[CloudFront.7] CloudFront distributions should use custom SSL / TLS certificates 日本語訳:CloudFront ディストリビューション では、カスタム SSL / TLS 証明書を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-7 英語タイトル:[CloudFront.8] CloudFront distributions should use SNI to serve HTTPS requests 日本語訳:CloudFront ディストリビューション では、SNI を使用して HTTPS リク エス トを処理する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-8 TLS 証明書を発行し、CloudFront ディストリビューション に関連付けます。 こうすることで自動的にSNIも有効になります。 コードを表示 const hostedZone = route53.PublicHostedZone.fromHostedZoneAttributes ( this , "MyHostedZone" , { hostedZoneId: hostedZoneId , // ホストゾーンID zoneName: hostedZoneName , // ホストゾーン名 } ); const cloudfrontCertificate = new certificatemanager.DnsValidatedCertificate ( this , "CloudFrontCertificate" , { domainName: "my-domain.com" , hostedZone: hostedZone , validation: certificatemanager.CertificateValidation.fromDns ( hostedZone ), } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , certificate: cloudfrontCertificate , domainNames: [ "my-domain.com" ] , } ); EC2 EC2.3 英語タイトル:Attached EBS volumes should be encrypted at rest 日本語訳:アタッチされた EBS ボリュームは、保管時の暗号化を有効に必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-3 AWS マネージドキーでの暗号化であれば blockDevices の encrypted プロパティで実現できます( 参考 )。 なお、リージョンで EBSボリュームのデフォルト暗号化 を設定しておくことによって、 blockDevices の encrypted プロパティを明示的に指定しなくても暗号化されるようになるので楽です。 コードを表示 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , blockDevices: [ { deviceName: "/dev/xvda" , mappingEnabled: true , volume: ec2.BlockDeviceVolume.ebs ( 30 , { deleteOnTermination: true , volumeType: ec2.EbsDeviceVolumeType.GP2 , encrypted: true , } ), } , ] , } ); EC2.8 英語タイトル:EC2 instances should use IMDSv2 日本語訳:EC2 インスタンス は IMDSv2 を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-8 requireImdsv2 プロパティで IMDSv2 のみを有効にします。EC2 インスタンス の通信内容によっては動作に問題が発生する可能性があるため、慎重な検証が必要です。 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , requireImdsv2: true , } ); SSM.1 英語タイトル:EC2 instances should be managed by AWS Systems Manager 日本語訳:EC2 インスタンス は AWS Systems Manager により管理される必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ssm-1 SSMでEC2 インスタンス を管理するためには いくつか条件 がありますが、特にハマりやすいのは以下の3点だと思います。( 参考 ) インスタンス にSSM エージェントがインストールされている SSMサービスへの通信ルートがある( VPC エンドポイント or インターネット経由) VPC エンドポイントの場合、 ssm 、 ec2messages 、 ssmmessages の3つが必要 インスタンス ロールが AmazonSSMManagedInstanceCore ポリシーを含んでいる 以下は SSM エージェントがインストールされている Amazon Linux 2を使用し、 VPC エンドポイントでSSMサービスに接続している例です。 コードを表示 const vpc = new ec2.Vpc ( this , "Vpc" , { subnetConfiguration: [ { name: "private-with-egress" , subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS , cidrMask: 20 , } , ] , } ); vpc.addInterfaceEndpoint ( "SSMEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "SSMMessagesEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "EC2MESSAGESEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); const role = new iam.Role ( this , "Role" , { assumedBy: new iam.ServicePrincipal ( "ec2.amazonaws.com" ), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName ( "AmazonSSMManagedInstanceCore" ) ] , } ); new ec2.Instance ( this , "Instance" , { vpc , role , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , } ); ECS ECS.5 英語タイトル:ECS containers should be limited to read-only access to root filesystems 日本語訳:ECS コンテナは、ルート ファイルシステム への読み取り専用アクセスに制限する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-5 ECSタスク定義のコンテナ定義で、 readonlyRootFilesystem を true とすることで ルートファイルシステムへのアクセスを読み取り専用 にします。ただしこの設定をするとコンテナの ファイルシステム に書き込むことができなくなり、 ECS Exec も使用できなくなります。 const taskDefinition = new ecs.FargateTaskDefinition ( this , "TaskDefinition" , { family: "my-task-definition" , runtimePlatform: { operatingSystemFamily: ecs.OperatingSystemFamily.LINUX } , } ); taskDefinition.addContainer ( "Container" , { containerName: "my-container" , image: ecs.ContainerImage.fromRegistry ( "my-ecr" ), readonlyRootFilesystem: true , } ); ECS.12 英語タイトル:ECS clusters should have Container Insights enabled 日本語訳:ECS クラスタ ーでは、Container Insights を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-12 ECS クラスタ ーの containerInsights プロパティを true にすることで、 Container Insights を有効にできます。 new ecs.Cluster ( this , "Cluster" , { vpc: vpc , containerInsights: true , } ); ECR ECR.1 英語タイトル:ECR private repositories should have image scanning configured 日本語訳:ECR プライベー トリポジ トリでは、イメージスキャニングが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-1 ECR リポジトリ の imageScanOnPush プロパティを true にすることで、 プッシュ時の基本スキャン を有効にできます。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageScanOnPush: true , } ); ECR.2 英語タイトル:ECR private repositories should have tag immutability configured 日本語訳:ECR プライベー トリポジ トリでは、タグのイミュータビリティが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-2 imageTagMutability を IMMUTABLE にすることで、 タグを変更不可 にします。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageTagMutability: ecr.TagMutability.IMMUTABLE , } ); ECR.3 英語タイトル:ECR repositories should have at least one lifecycle policy configured 日本語訳:ECR リポジトリ には、少なくとも 1 つのライフサイクルポリシーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-3 lifecycleRules プロパティを設定することで、 ECRリポジトリのライフライクルポリシー を設定します。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , lifecycleRules: [{ maxImageCount: 5 }] , } ); RDS RDS.3 英語タイトル:RDS DB instances should have encryption at rest enabled 日本語訳:RDS DB インスタンス では、保管時の暗号化が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-3 storageEncrypted プロパティでストレージの暗号化を有効化します。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , storageEncrypted: true , } ); RDS.7、RDS.8 英語タイトル:[RDS.7] RDS clusters should have deletion protection enabled 日本語訳:RDS クラスタ ーでは、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-7 英語タイトル:[RDS.8] RDS DB instances should have deletion protection enabled 日本語訳:RDS DB インスタンス で、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-8 deletionProtection か removalPolicy のどちらかのプロパティを使用して、削除保護を有効にします。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); RDS.9 英語タイトル:Database logging should be enabled 日本語訳:データベースログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-9 MySQL と PostgreSQL でルールをクリアするために有効にしなければならないログが異なります。 試した際には、 MySQL では「エラーログ」「一般ログ」「スロークエリログ」の3つを最低限出力していればルールはクリアになりました。 PostgreSQL では「 PostgreSQL ログ」と「アップグレードログ」の両方を出力する必要がありました。 const mysqlParameterGroup = new rds.ParameterGroup ( this , "MysqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.mysql ( { version: rds.MysqlEngineVersion.VER_8_0 , } ), parameters: { general_log: "1" , slow_query_log: "1" , log_output: "FILE" , } , } ); new rds.DatabaseInstance ( this , "Mysql" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: mysqlParameterGroup , // 監査ログも含める場合は "audit" を追加 cloudwatchLogsExports: [ "error" , "general" , "slowquery" ] , } ); const postgresParameterGroup = new rds.ParameterGroup ( this , "PostgresqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.postgres ( { version: rds.PostgresEngineVersion.VER_14 , } ), parameters: { log_statement: "all" , } , } ); new rds.DatabaseInstance ( this , "Postgresql" , { vpc , engine: rds.DatabaseInstanceEngine.POSTGRES , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: postgresParameterGroup , cloudwatchLogsExports: [ "postgresql" , "upgrade" ] , } ); (2023/4/19追記)ログ出力に際し、パラメータグループの設定が抜けていたため追記しました。詳細は以下。 https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.MySQL.LogFileSize.html https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.PostgreSQL.html RDS.10、RDS.12 英語タイトル:[RDS.10] IAM authentication should be configured for RDS instances 日本語訳:IAM 認証は RDS インスタンス 用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-10 英語タイトル:[RDS.12] IAM authentication should be configured for RDS clusters 日本語訳:IAM 認証は RDS クラスタ ー用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-12 iamAuthentication プロパティを true にすることで、RDSへの接続に IAM認証 を利用できます。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , iamAuthentication: true , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , iamAuthentication: true , } ); RDS.11 英語タイトル: Amazon RDS instances should have automatic backups enabled 日本語訳: Amazon RDS インスタンス では、自動バックアップが有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-11 backupRetention プロパティを使用して 自動バックアップ を設定し、7日以上にすることでルールをクリアできます。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // 7日以上にする backupRetention: cdk.Duration.days ( 7 ), } ); RDS.13 英語タイトル:RDS automatic minor version upgrades should be enabled 日本語訳:RDS 自動マイナーバージョンアップグレードを有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-13 CDKでRDS インスタンス を作成すると、DBエンジンのマイナーバージョンアップグレードはデフォルトで有効ですが、メンテナンスウィンドウは自動的に選択されるため、 preferredMaintenanceWindow で指定すると良いでしょう。なお、 UTC で記載する必要があることにご注意ください。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , autoMinorVersionUpgrade: true , // デフォルトでも true preferredMaintenanceWindow: "sat:18:00-sat:18:30" , // メンテナンスウィンドウ (UTC) } ); RDS.14 英語タイトル: Amazon Aurora clusters should have backtracking enabled 日本語訳: Amazon Aurora クラスタ ーはバックト ラッキング を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-14 Aurora クラスタ ーの backtrackWindow プロパティでバックトラックウィンドウを指定することで、 バックトラック を有効にできます。 new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , backtrackWindow: cdk.Duration.hours ( 24 ), } ); RDS.23 英語タイトル:RDS databases and clusters should not use a database engine default port 日本語訳:RDS データベースと クラスタ ーはデータベースエンジンのデフォルトポートを使用しないでください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-23 port プロパティにより接続ポートをデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , port: 13306 , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , port: 13306 , } ); RDS.24、RDS.25 英語タイトル:[RDS.24] RDS database clusters should use a custom administrator username 日本語訳:RDS データベース クラスタ ーはカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-24 英語タイトル:[RDS.25] RDS database instances should use a custom administrator username 日本語訳:RDS データベース インスタンス はカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-25 credentials プロパティで、管理者ユーザー名をデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); DynamoDB DynamoDB.2 英語タイトル:DynamoDB tables should have point-in-time recovery enabled 日本語訳:DynamoDB テーブルでは、ポイントインタ イムリ カバリが有効になっている必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-dynamodb-2 pointInTimeRecovery プロパティで ポイントインタイムリカバリ を有効にできます。 new dynamodb.Table ( this , "Table" , { partitionKey: { name: "pk" , type : dynamodb.AttributeType.STRING } , sortKey: { name: "sk" , type : dynamodb.AttributeType.STRING } , pointInTimeRecovery: true , } ); S3 S3.4 英語タイトル:S3 buckets should have server-side encryption enabled 日本語訳:S3 バケット では、サーバーサイドの暗号化を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-4 以下の例はS3マネージドの鍵(SSE-S3)を使ってS3 バケット の サーバサイド暗号化 を設定する例です。 new s3.Bucket ( this , "Bucket" , { encryption: s3.BucketEncryption.S3_MANAGED , } ); S3.5 英語タイトル:S3 buckets should require requests to use Secure Socket Layer 日本語訳:S3 バケット では、Secure Socket Layer を使用するためのリク エス トの要求が必要です https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-5 暗号化されていない通信を拒否する にはS3 バケット ポリシーを設定しますが、CDKでは enforceSSL プロパティで簡単に バケット ポリシーを追加してくれます。 new s3.Bucket ( this , "Bucket" , { enforceSSL: true , } ); S3.8 英語タイトル:S3 Block Public Access setting should be enabled at the bucket level 日本語訳:S3 ブロックパブリックアクセス設定は、 バケット レベルで有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-8 4つの ブロックパブリックアクセス 設定を全て有効にするには、 blockPublicAccess プロパティに BLOCK_ALL を指定します。 new s3.Bucket ( this , "Bucket" , { blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL , } ); S3.9 英語タイトル:S3 bucket server access logging should be enabled 日本語訳:S3 バケット サーバー アクセスログ 記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-9 serverAccessLogsBucket プロパティでS3 バケット の サーバーアクセスログ を出力する先のS3 バケット を、 serverAccessLogsPrefix プロパティで プレフィックス を指定します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new s3.Bucket ( this , "Bucket" , { serverAccessLogsBucket: logBucket , serverAccessLogsPrefix: "prefix" , } ); S3.13 英語タイトル:S3 buckets should have lifecycle policies configured 日本語訳:S3 バケット では、ライフサイクルポリシーを設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-13 lifecycleRules プロパティでS3 バケット の ライフサイクルポリシー を設定します。以下の例は30日後にIAクラスにオブジェクトを移動し、90日後にオブジェクトを削除するポリシーです。 new s3.Bucket ( this , "Bucket" , { lifecycleRules: [ { id: "log lifecycle" , transitions: [ { storageClass: s3.StorageClass.INFREQUENT_ACCESS , transitionAfter: cdk.Duration.days ( 30 ), } , ] , expiration: cdk.Duration.days ( 90 ), } , ] , } ); EFS EFS.1 英語タイトル: Amazon EFS should be configured to encrypt file data at rest using AWS KMS 日本語訳: Amazon EFS は、 AWS KMS を使用して保管中のファイルデータを暗号化するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-efs-1 encrypted プロパティで暗号化を設定しますが、CDK v2 ではデフォルト true なので、特別な実装は必要ありません。 (ドキュメントでは @aws-cdk/aws-efs:defaultEncryptionAtRest フィーチャーフラグを有効にしない限り encrypted のデフォルトは false である、とありますが、CDK v2ではこのフィーチャーフラグは廃止されており、有効になっているのと同じ動きになっています) new efs.FileSystem ( this , "FileSystem" , { vpc , encrypted: true , // CDK v2 ではデフォルトで true } ); SNS SNS .1 英語タイトル: SNS topics should be encrypted at rest using AWS KMS 日本語訳: SNS トピックは、 AWS KMS を使用して保管時に暗号化する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-1 次のように暗号化に利用するKMSキーを取得し、 masterKey プロパティに渡すことで暗号化されます。 ※トピックがCloudWatch AlarmやEventbridgeルールのターゲットの場合、デフォルトキー(alias/ aws / sns )を利用できないため要注意です。 https://repost.aws/ja/knowledge-center/cloudwatch-receive-sns-for-alarm-trigger https://repost.aws/ja/knowledge-center/sns-not-getting-eventbridge-notification const key = kms.Key.fromLookup ( this , "SNSKey" , { aliasName: "alias/aws/sns" } ); new sns.Topic ( this , "Topic2" , { masterKey: key , } ); SNS .2 英語タイトル:Logging of delivery status should be enabled for notification messages sent to a topic 日本語訳:トピックに送信される通知メッセージでは、配信ステータスのログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-2 配信ステータスのログ記録 はCloudFormationでもサポートされておらず、CDKで実装するにはカスタムリソースで SDK 呼び出しをする必要があり( 参考 )、大変です。今後のアップデートに期待します。 SQS SQS.1 英語タイトル: Amazon SQS queues should be encrypted at rest 日本語訳: Amazon SQS キューは保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sqs-1 2022年10月より、新しく作成されるSQSキューは デフォルトで暗号化される ようになったため、特別な実装は不要になりました。 new sqs.Queue ( this , "Queue" , { // 指定しなくても新規作成されるキューはデフォルトで暗号化される encryption: sqs.QueueEncryption.SQS_MANAGED , } ); API Gateway APIGateway.1 英語タイトル: API Gateway REST and WebSocket API logging should be enabled 日本語訳: API Gateway REST および WebSocket API ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-1 CloudWatch Logs ロググループを作成し、 loggingLevel 、 accessLogDestination 、 accessLogFormat プロパティで ログの出力 を設定します。 const log = new logs.LogGroup ( this , "ApiGatewayLog" , { logGroupName: "api-gateway-log" , retention: logs.RetentionDays.SIX_MONTHS , } ); new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , loggingLevel: apigateway.MethodLoggingLevel.INFO , accessLogDestination: new apigateway.LogGroupLogDestination ( log ), accessLogFormat: apigateway.AccessLogFormat.clf (), } , } ); APIGateway.4 英語タイトル: API Gateway should be associated with an AWS WAF web ACL 日本語訳: API Gateway は、 AWS WAF ウェブ ACL に関連付けられている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-4 AWS WAFのWeb ACL を作成し、 API Gateway のステージに関連付けます。 コードを表示 const api = new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , } , } ); const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAcl" , { defaultAction: { allow: {} } , // scopeは REGIONAL とする scope: "REGIONAL" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "wafWebAcl" , } , rules: [ { // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); const webAclAssociation = new wafv2.CfnWebACLAssociation ( this , "WebAclAssociation" , { resourceArn: `arn:aws:apigateway: ${ region } ::/restapis/ ${ api4.restApiId } /stages/dev` , webAclArn: wafWebAcl.attrArn , } ); webAclAssociation.addDependsOn ( wafWebAcl ); webAclAssociation.addDependsOn ( api.deploymentStage.node.defaultChild as cdk.CfnResource ); APIGateway.5 英語タイトル: API Gateway REST API cache data should be encrypted at rest 日本語訳: API Gateway REST API のキャッシュデータは、保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-5 cachingEnabled を true にすることでこのルールの検出対象になり、 cacheDataEncrypted プロパティでキャッシュデータの暗号化を有効にできます。 new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , cachingEnabled: true , cacheDataEncrypted: true , } , } ); 大変長い記事になりました。読んでいただき、ありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。これは 電通国際情報サービス Advent Calendar 2022 12/14の記事です。 プログラミング言語 で クラウド インフラをIaC化できるライブラリとして、 AWS Cloud Development Kit (CDK) が使われることが増えています。CDKではリソースのデフォルト値が設定され、便利に短く記述できる一方で、デフォルト値が必ずしも推奨されるセキュリティ構成になっていない場合があります。 Security Hubのセキュリティ基準 を利用していると、リソースをデプロイした後にアラートに気付いて修正をすることもあるのではないでしょうか。 そこでこの記事では、Security Hubのセキュリティ基準でアラートを出さないためのCDKによるリソースの記述方法を、主要なサービスの種類ごとにまとめました。CDKでリソースを作成するときに、どのような設定を気にした方が良いのか、Security Hubアラートとの マッピング として使っていただけると幸いです。 なお、矛盾しているように聞こえるかもしれませんが、Security Hubのチェックルールは 全てクリアすること自体を目的とするものではない と考えています。 AWS も全てのルールをクリアすることを期待していないでしょう。例えばS3 バケット については、 アクセスログ を出力するようにチェックするルールがありますが(S3.9)、 アクセスログ を格納する バケット の アクセスログ は出力しないため、全くアラートが上がらない状態にはできませんね。闇雲に全てのSecurity Hubアラートをクリアしようとするのではなく、 アラートからリスクを評価し、対応するかどうかを総合的に判断する プロセスが必要です。「知らずに設定していなかった」ではなく、「知った上で設定するかどうか判断する」状態にするために、Security Hubを活用するのが良いと思います。 おことわり セキュリティ基準として、記事執筆時点の AWS Foundational Security Best Practices を対象とします AWS Foundational Security Best Practices では、30以上の AWS サービスについてのコン トロール (チェックルール)がありますが、この記事ではよく使われるサービスで、CDKで作成することが多いと思われる13種のサービスのみを取り上げます 全てのコン トロール を網羅していません。CDKのデフォルト設定で対応できていないコン トロール を中心に扱います。また可用性に関わるコン トロール や、要件に応じて特別な構成が必要なコン トロール は除外しているものがあります 設定自体の意味、設定することによる影響は割愛しているため、公式ドキュメントなどでご確認ください 設定することによって追加でかかる費用については、記事内では言及していません 記載しているコードは実装方法の一つの例であり、他にも実装方法がある場合があります コード例は分かりやすさのため、関連する最小限のリソースプロパティのみ記載しています CDKで対応できる範囲、かつSecurity Hubのセキュリティ基準の範囲のセキュリティ対策であるため、当然ながらこれらの設定だけをすれば他にセキュリティ対策が不要というわけではありません CDK v2.50.0 で検証しています。今後のアップデートにより実装方法が変更になったり、デフォルトの挙動が変わる可能性があります。 AWS ドキュメントでは一部不自然な日本語訳があるため、わかりやすさのため独自の日本語訳にしているコン トロール があります。 おことわり VPC EC2.2 EC2.6 EC2.18、EC2.19 ELB ELB.4 ELB.5 ELB.6 CloudFront CloudFront.1 CloudFront.2 CloudFront.3 CloudFront.4 CloudFront.5 CloudFront.6 CloudFront.7、CloudFront.8 EC2 EC2.3 EC2.8 SSM.1 ECS ECS.5 ECS.12 ECR ECR.1 ECR.2 ECR.3 RDS RDS.3 RDS.7、RDS.8 RDS.9 RDS.10、RDS.12 RDS.11 RDS.13 RDS.14 RDS.23 RDS.24、RDS.25 DynamoDB DynamoDB.2 S3 S3.4 S3.5 S3.8 S3.9 S3.13 EFS EFS.1 SNS SNS.1 SNS.2 SQS SQS.1 API Gateway APIGateway.1 APIGateway.4 APIGateway.5 VPC EC2.2 英語タイトル:The VPC default security group should not allow inbound and outbound traffic 日本語訳: VPC のデフォルトのセキュリティグループでは、インバウンド トラフィック とアウトバウンド トラフィック を許可しないようにする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-2 (2023/6/27更新). CDK v2.78.0より、 Vpc で restrictDefaultSecurityGroup プロパティが利用できるようになったため、対応が簡単になりました。 new Vpc ( this , "Vpc" , { restrictDefaultSecurityGroup: true , } ); ======以下は過去の対応方法です。====== CDKでは簡単にデフォルトのセキュリティグループのルールを変更できないため、現時点では この投稿 の通り、カスタムリソースを利用してルールを削除することになります。 まずは Vpc を継承した BaseVpc というクラスを作り(名前自由)、セキュリティグループのルールを削除するカスタムリソースを含めます。 コードを表示 import { Stack } from "aws-cdk-lib" ; import { CfnVPC , Vpc , VpcProps } from "aws-cdk-lib/aws-ec2" ; import { AwsCustomResource , AwsCustomResourcePolicy , PhysicalResourceId } from "aws-cdk-lib/custom-resources" ; import { Construct } from "constructs" ; export class BaseVpc extends Vpc { constructor( scope: Construct , id: string , props: VpcProps ) { super( scope , id , props ); const cfnVpc = this .node.defaultChild as CfnVPC ; const stack = Stack. of( this ); const ingressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , UserIdGroupPairs: [ { GroupId: cfnVpc.attrDefaultSecurityGroup , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupIngress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupIngress" , parameters: ingressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-ingress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupIngress" , parameters: ingressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); const egressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , IpRanges: [ { CidrIp: "0.0.0.0/0" , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupEgress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupEgress" , parameters: egressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-egress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupEgress" , parameters: egressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); } } それを Vpc の代わりに利用するだけです。 new BaseVpc ( this , "Vpc" , {} ); ======過去の対応方法ここまで====== EC2.6 英語タイトル: VPC flow logging should be enabled in all VPCs 日本語訳:すべての VPC で VPC フローログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-6 VPCフローログ を有効にします。以下の例ではS3 バケット に出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const vpc = new ec2.Vpc ( this , "Vpc" , {} ); new ec2.FlowLog ( this , "VpcFlowLog" , { resourceType: ec2.FlowLogResourceType.fromVpc ( vpc ), destination: ec2.FlowLogDestination.toS3 ( logBucket , "vpc/" ), trafficType: ec2.FlowLogTrafficType.ALL , } ); EC2.18、EC2.19 英語タイトル:[EC2.18] Security groups should only allow unrestricted incoming traffic for authorized ports 日本語訳:セキュリティグループは、許可されたポートのみに対して制限されていない着信 トラフィック を許可してください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-18 英語タイトル:[EC2.19] Security groups should not allow unrestricted access to ports with high risk 日本語訳:セキュリティグループは、リスクの高いポートへの無制限アクセスを許可してはいけません https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-19 この2つは関連するコン トロール であり、チェック対象となるポート番号だけが異なるので一緒に扱います。 セキュリティグループにHTTP(80)、 HTTPS (443)以外のポートへのインバウンドルールを追加する時は無制限アクセス(0.0.0.0/0)を許可するのではなく、送信元 IPアドレス か特定のセキュリティグループに制限します。 const sshSecurityGroup = new ec2.SecurityGroup ( this , "SecurityGroup" , { vpc , } ); const anotherSecurityGroup = new ec2.SecurityGroup ( this , "AnotherSecurityGroup" , { vpc , } ); // 許可するIPアドレスレンジを制限する sshSecurityGroup.addIngressRule ( ec2.Peer.ipv4 ( "xx.xx.xx.xx/32" ), ec2.Port.tcp ( 22 )); // 別のセキュリティグループに制限する sshSecurityGroup.addIngressRule ( anotherSecurityGroup , ec2.Port.tcp ( 22 )); ELB ELB.4 英語タイトル:Application load balancers should be configured to drop HTTP headers 日本語訳:Application Load Balancer は、HTTP ヘッダーを削除するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-4 dropInvalidHeaderFields プロパティ(CDK v2.47.0~)を利用し、 無効なHTTPヘッダーの削除設定 を有効にします。 new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , dropInvalidHeaderFields: true , } ); ELB.5 英語タイトル:Application and Classic Load Balancers logging should be enabled 日本語訳:Application Load Balancer および Classic Load Balancer のログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-5 ロードバランサーのアクセスログ をS3 バケット に保存します。以下の例はALBの場合です。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , } ); alb.logAccessLogs ( logBucket , "alb" ); ELB.6 英語タイトル:Application Load Balancer deletion protection should be enabled 日本語訳:Application Load Balancer で削除保護を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-6 deletionProtection プロパティを利用し、 削除保護 を有効にします。 const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , deletionProtection: true , } ); CloudFront CloudFront.1 英語タイトル:CloudFront distributions should have a default root object configured 日本語訳:CloudFront ディストリビューション では、デフォルトのルートオブジェクトが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-1 以下の例はS3 バケット がオリジンの場合です。あらかじめ ルートオブジェクト をアップロードした上で、 defaultRootObject プロパティでオブジェクトパスを指定します。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , defaultRootObject: "index.html" , } ); CloudFront.2 英語タイトル:CloudFront distributions should have origin access identity enabled 日本語訳:CloudFront ディストリビューション では、オリジンアクセス アイデンティティ を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-2 CDKではCloudFront ディストリビューション のオリジンをS3 バケット に指定するだけで、 OAI が自動的に設定され、特別な実装は必要ありません。 なお、OAIに代わる OAC については、記事執筆時点では CDKのL2コンストラクトでは未対応 です。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , } ); CloudFront.3 英語タイトル:CloudFront distributions should require encryption in transit 日本語訳:CloudFront ディストリビューション では、転送中に暗号化が必要となります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-3 viewerProtocolPolicy を REDIRECT_TO_HTTPS もしくは HTTPS_ONLY にすることで対応できます。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS , } , } ); CloudFront.4 英語タイトル:CloudFront distributions should have origin failover configured 日本語訳:CloudFront ディストリビューション では、オリジンフェイルオーバーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-4 フェイルオーバー 用のオリジンを別途作成し、 OriginGroup で primaryOrigin と fallbackOrigin を設定します。(「フェイルオーバー」と「フェイルバック」の用語が統一されていませんが、同じものを指していると考えて良いでしょう) const fallbackBucket = new s3.Bucket ( this , "FallbackBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.OriginGroup ( { primaryOrigin: new cloudfrontOrigins.S3Origin ( originBucket ), fallbackOrigin: new cloudfrontOrigins.S3Origin ( fallbackBucket ), } ), } , } ); CloudFront.5 英語タイトル:CloudFront distributions should have logging enabled 日本語訳:CloudFront ディストリビューション では、ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-5 logBucket と logFilePrefix プロパティを指定し、 CloudFrontのログ を出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , logBucket: logBucket , logFilePrefix: "cloudfront/" , } ); CloudFront.6 英語タイトル:CloudFront distributions should have AWS WAF enabled 日本語訳:CloudFront ディストリビューション では、 AWS WAF を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-6 AWS WAFのWeb ACL を作成し、CloudFront ディストリビューション に関連付けます。 コードを表示 const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAclCloudFront" , { defaultAction: { allow: {} } , // scopeは CLOUDFRONT とする scope: "CLOUDFRONT" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "WafV2WebAclCloudFront" , } , rules: [ // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ { name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , webAclId: wafWebAcl.attrArn , } ); CloudFront.7、CloudFront.8 英語タイトル:[CloudFront.7] CloudFront distributions should use custom SSL / TLS certificates 日本語訳:CloudFront ディストリビューション では、カスタム SSL / TLS 証明書を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-7 英語タイトル:[CloudFront.8] CloudFront distributions should use SNI to serve HTTPS requests 日本語訳:CloudFront ディストリビューション では、SNI を使用して HTTPS リク エス トを処理する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-8 TLS 証明書を発行し、CloudFront ディストリビューション に関連付けます。 こうすることで自動的にSNIも有効になります。 コードを表示 const hostedZone = route53.PublicHostedZone.fromHostedZoneAttributes ( this , "MyHostedZone" , { hostedZoneId: hostedZoneId , // ホストゾーンID zoneName: hostedZoneName , // ホストゾーン名 } ); const cloudfrontCertificate = new certificatemanager.DnsValidatedCertificate ( this , "CloudFrontCertificate" , { domainName: "my-domain.com" , hostedZone: hostedZone , validation: certificatemanager.CertificateValidation.fromDns ( hostedZone ), } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , certificate: cloudfrontCertificate , domainNames: [ "my-domain.com" ] , } ); EC2 EC2.3 英語タイトル:Attached EBS volumes should be encrypted at rest 日本語訳:アタッチされた EBS ボリュームは、保管時の暗号化を有効に必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-3 AWS マネージドキーでの暗号化であれば blockDevices の encrypted プロパティで実現できます( 参考 )。 なお、リージョンで EBSボリュームのデフォルト暗号化 を設定しておくことによって、 blockDevices の encrypted プロパティを明示的に指定しなくても暗号化されるようになるので楽です。 コードを表示 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , blockDevices: [ { deviceName: "/dev/xvda" , mappingEnabled: true , volume: ec2.BlockDeviceVolume.ebs ( 30 , { deleteOnTermination: true , volumeType: ec2.EbsDeviceVolumeType.GP2 , encrypted: true , } ), } , ] , } ); EC2.8 英語タイトル:EC2 instances should use IMDSv2 日本語訳:EC2 インスタンス は IMDSv2 を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-8 requireImdsv2 プロパティで IMDSv2 のみを有効にします。EC2 インスタンス の通信内容によっては動作に問題が発生する可能性があるため、慎重な検証が必要です。 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , requireImdsv2: true , } ); SSM.1 英語タイトル:EC2 instances should be managed by AWS Systems Manager 日本語訳:EC2 インスタンス は AWS Systems Manager により管理される必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ssm-1 SSMでEC2 インスタンス を管理するためには いくつか条件 がありますが、特にハマりやすいのは以下の3点だと思います。( 参考 ) インスタンス にSSM エージェントがインストールされている SSMサービスへの通信ルートがある( VPC エンドポイント or インターネット経由) VPC エンドポイントの場合、 ssm 、 ec2messages 、 ssmmessages の3つが必要 インスタンス ロールが AmazonSSMManagedInstanceCore ポリシーを含んでいる 以下は SSM エージェントがインストールされている Amazon Linux 2を使用し、 VPC エンドポイントでSSMサービスに接続している例です。 コードを表示 const vpc = new ec2.Vpc ( this , "Vpc" , { subnetConfiguration: [ { name: "private-with-egress" , subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS , cidrMask: 20 , } , ] , } ); vpc.addInterfaceEndpoint ( "SSMEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "SSMMessagesEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "EC2MESSAGESEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); const role = new iam.Role ( this , "Role" , { assumedBy: new iam.ServicePrincipal ( "ec2.amazonaws.com" ), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName ( "AmazonSSMManagedInstanceCore" ) ] , } ); new ec2.Instance ( this , "Instance" , { vpc , role , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , } ); ECS ECS.5 英語タイトル:ECS containers should be limited to read-only access to root filesystems 日本語訳:ECS コンテナは、ルート ファイルシステム への読み取り専用アクセスに制限する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-5 ECSタスク定義のコンテナ定義で、 readonlyRootFilesystem を true とすることで ルートファイルシステムへのアクセスを読み取り専用 にします。ただしこの設定をするとコンテナの ファイルシステム に書き込むことができなくなり、 ECS Exec も使用できなくなります。 const taskDefinition = new ecs.FargateTaskDefinition ( this , "TaskDefinition" , { family: "my-task-definition" , runtimePlatform: { operatingSystemFamily: ecs.OperatingSystemFamily.LINUX } , } ); taskDefinition.addContainer ( "Container" , { containerName: "my-container" , image: ecs.ContainerImage.fromRegistry ( "my-ecr" ), readonlyRootFilesystem: true , } ); ECS.12 英語タイトル:ECS clusters should have Container Insights enabled 日本語訳:ECS クラスタ ーでは、Container Insights を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-12 ECS クラスタ ーの containerInsights プロパティを true にすることで、 Container Insights を有効にできます。 new ecs.Cluster ( this , "Cluster" , { vpc: vpc , containerInsights: true , } ); ECR ECR.1 英語タイトル:ECR private repositories should have image scanning configured 日本語訳:ECR プライベー トリポジ トリでは、イメージスキャニングが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-1 ECR リポジトリ の imageScanOnPush プロパティを true にすることで、 プッシュ時の基本スキャン を有効にできます。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageScanOnPush: true , } ); ECR.2 英語タイトル:ECR private repositories should have tag immutability configured 日本語訳:ECR プライベー トリポジ トリでは、タグのイミュータビリティが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-2 imageTagMutability を IMMUTABLE にすることで、 タグを変更不可 にします。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageTagMutability: ecr.TagMutability.IMMUTABLE , } ); ECR.3 英語タイトル:ECR repositories should have at least one lifecycle policy configured 日本語訳:ECR リポジトリ には、少なくとも 1 つのライフサイクルポリシーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-3 lifecycleRules プロパティを設定することで、 ECRリポジトリのライフライクルポリシー を設定します。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , lifecycleRules: [{ maxImageCount: 5 }] , } ); RDS RDS.3 英語タイトル:RDS DB instances should have encryption at rest enabled 日本語訳:RDS DB インスタンス では、保管時の暗号化が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-3 storageEncrypted プロパティでストレージの暗号化を有効化します。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , storageEncrypted: true , } ); RDS.7、RDS.8 英語タイトル:[RDS.7] RDS clusters should have deletion protection enabled 日本語訳:RDS クラスタ ーでは、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-7 英語タイトル:[RDS.8] RDS DB instances should have deletion protection enabled 日本語訳:RDS DB インスタンス で、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-8 deletionProtection か removalPolicy のどちらかのプロパティを使用して、削除保護を有効にします。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); RDS.9 英語タイトル:Database logging should be enabled 日本語訳:データベースログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-9 MySQL と PostgreSQL でルールをクリアするために有効にしなければならないログが異なります。 試した際には、 MySQL では「エラーログ」「一般ログ」「スロークエリログ」の3つを最低限出力していればルールはクリアになりました。 PostgreSQL では「 PostgreSQL ログ」と「アップグレードログ」の両方を出力する必要がありました。 const mysqlParameterGroup = new rds.ParameterGroup ( this , "MysqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.mysql ( { version: rds.MysqlEngineVersion.VER_8_0 , } ), parameters: { general_log: "1" , slow_query_log: "1" , log_output: "FILE" , } , } ); new rds.DatabaseInstance ( this , "Mysql" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: mysqlParameterGroup , // 監査ログも含める場合は "audit" を追加 cloudwatchLogsExports: [ "error" , "general" , "slowquery" ] , } ); const postgresParameterGroup = new rds.ParameterGroup ( this , "PostgresqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.postgres ( { version: rds.PostgresEngineVersion.VER_14 , } ), parameters: { log_statement: "all" , } , } ); new rds.DatabaseInstance ( this , "Postgresql" , { vpc , engine: rds.DatabaseInstanceEngine.POSTGRES , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: postgresParameterGroup , cloudwatchLogsExports: [ "postgresql" , "upgrade" ] , } ); (2023/4/19追記)ログ出力に際し、パラメータグループの設定が抜けていたため追記しました。詳細は以下。 https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.MySQL.LogFileSize.html https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.PostgreSQL.html RDS.10、RDS.12 英語タイトル:[RDS.10] IAM authentication should be configured for RDS instances 日本語訳:IAM 認証は RDS インスタンス 用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-10 英語タイトル:[RDS.12] IAM authentication should be configured for RDS clusters 日本語訳:IAM 認証は RDS クラスタ ー用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-12 iamAuthentication プロパティを true にすることで、RDSへの接続に IAM認証 を利用できます。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , iamAuthentication: true , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , iamAuthentication: true , } ); RDS.11 英語タイトル: Amazon RDS instances should have automatic backups enabled 日本語訳: Amazon RDS インスタンス では、自動バックアップが有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-11 backupRetention プロパティを使用して 自動バックアップ を設定し、7日以上にすることでルールをクリアできます。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // 7日以上にする backupRetention: cdk.Duration.days ( 7 ), } ); RDS.13 英語タイトル:RDS automatic minor version upgrades should be enabled 日本語訳:RDS 自動マイナーバージョンアップグレードを有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-13 CDKでRDS インスタンス を作成すると、DBエンジンのマイナーバージョンアップグレードはデフォルトで有効ですが、メンテナンスウィンドウは自動的に選択されるため、 preferredMaintenanceWindow で指定すると良いでしょう。なお、 UTC で記載する必要があることにご注意ください。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , autoMinorVersionUpgrade: true , // デフォルトでも true preferredMaintenanceWindow: "sat:18:00-sat:18:30" , // メンテナンスウィンドウ (UTC) } ); RDS.14 英語タイトル: Amazon Aurora clusters should have backtracking enabled 日本語訳: Amazon Aurora クラスタ ーはバックト ラッキング を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-14 Aurora クラスタ ーの backtrackWindow プロパティでバックトラックウィンドウを指定することで、 バックトラック を有効にできます。 new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , backtrackWindow: cdk.Duration.hours ( 24 ), } ); RDS.23 英語タイトル:RDS databases and clusters should not use a database engine default port 日本語訳:RDS データベースと クラスタ ーはデータベースエンジンのデフォルトポートを使用しないでください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-23 port プロパティにより接続ポートをデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , port: 13306 , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , port: 13306 , } ); RDS.24、RDS.25 英語タイトル:[RDS.24] RDS database clusters should use a custom administrator username 日本語訳:RDS データベース クラスタ ーはカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-24 英語タイトル:[RDS.25] RDS database instances should use a custom administrator username 日本語訳:RDS データベース インスタンス はカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-25 credentials プロパティで、管理者ユーザー名をデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); DynamoDB DynamoDB.2 英語タイトル:DynamoDB tables should have point-in-time recovery enabled 日本語訳:DynamoDB テーブルでは、ポイントインタ イムリ カバリが有効になっている必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-dynamodb-2 pointInTimeRecovery プロパティで ポイントインタイムリカバリ を有効にできます。 new dynamodb.Table ( this , "Table" , { partitionKey: { name: "pk" , type : dynamodb.AttributeType.STRING } , sortKey: { name: "sk" , type : dynamodb.AttributeType.STRING } , pointInTimeRecovery: true , } ); S3 S3.4 英語タイトル:S3 buckets should have server-side encryption enabled 日本語訳:S3 バケット では、サーバーサイドの暗号化を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-4 以下の例はS3マネージドの鍵(SSE-S3)を使ってS3 バケット の サーバサイド暗号化 を設定する例です。 new s3.Bucket ( this , "Bucket" , { encryption: s3.BucketEncryption.S3_MANAGED , } ); S3.5 英語タイトル:S3 buckets should require requests to use Secure Socket Layer 日本語訳:S3 バケット では、Secure Socket Layer を使用するためのリク エス トの要求が必要です https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-5 暗号化されていない通信を拒否する にはS3 バケット ポリシーを設定しますが、CDKでは enforceSSL プロパティで簡単に バケット ポリシーを追加してくれます。 new s3.Bucket ( this , "Bucket" , { enforceSSL: true , } ); S3.8 英語タイトル:S3 Block Public Access setting should be enabled at the bucket level 日本語訳:S3 ブロックパブリックアクセス設定は、 バケット レベルで有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-8 4つの ブロックパブリックアクセス 設定を全て有効にするには、 blockPublicAccess プロパティに BLOCK_ALL を指定します。 new s3.Bucket ( this , "Bucket" , { blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL , } ); S3.9 英語タイトル:S3 bucket server access logging should be enabled 日本語訳:S3 バケット サーバー アクセスログ 記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-9 serverAccessLogsBucket プロパティでS3 バケット の サーバーアクセスログ を出力する先のS3 バケット を、 serverAccessLogsPrefix プロパティで プレフィックス を指定します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new s3.Bucket ( this , "Bucket" , { serverAccessLogsBucket: logBucket , serverAccessLogsPrefix: "prefix" , } ); S3.13 英語タイトル:S3 buckets should have lifecycle policies configured 日本語訳:S3 バケット では、ライフサイクルポリシーを設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-13 lifecycleRules プロパティでS3 バケット の ライフサイクルポリシー を設定します。以下の例は30日後にIAクラスにオブジェクトを移動し、90日後にオブジェクトを削除するポリシーです。 new s3.Bucket ( this , "Bucket" , { lifecycleRules: [ { id: "log lifecycle" , transitions: [ { storageClass: s3.StorageClass.INFREQUENT_ACCESS , transitionAfter: cdk.Duration.days ( 30 ), } , ] , expiration: cdk.Duration.days ( 90 ), } , ] , } ); EFS EFS.1 英語タイトル: Amazon EFS should be configured to encrypt file data at rest using AWS KMS 日本語訳: Amazon EFS は、 AWS KMS を使用して保管中のファイルデータを暗号化するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-efs-1 encrypted プロパティで暗号化を設定しますが、CDK v2 ではデフォルト true なので、特別な実装は必要ありません。 (ドキュメントでは @aws-cdk/aws-efs:defaultEncryptionAtRest フィーチャーフラグを有効にしない限り encrypted のデフォルトは false である、とありますが、CDK v2ではこのフィーチャーフラグは廃止されており、有効になっているのと同じ動きになっています) new efs.FileSystem ( this , "FileSystem" , { vpc , encrypted: true , // CDK v2 ではデフォルトで true } ); SNS SNS .1 英語タイトル: SNS topics should be encrypted at rest using AWS KMS 日本語訳: SNS トピックは、 AWS KMS を使用して保管時に暗号化する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-1 次のように暗号化に利用するKMSキーを取得し、 masterKey プロパティに渡すことで暗号化されます。 ※トピックがCloudWatch AlarmやEventbridgeルールのターゲットの場合、デフォルトキー(alias/ aws / sns )を利用できないため要注意です。 https://repost.aws/ja/knowledge-center/cloudwatch-receive-sns-for-alarm-trigger https://repost.aws/ja/knowledge-center/sns-not-getting-eventbridge-notification const key = kms.Key.fromLookup ( this , "SNSKey" , { aliasName: "alias/aws/sns" } ); new sns.Topic ( this , "Topic2" , { masterKey: key , } ); SNS .2 英語タイトル:Logging of delivery status should be enabled for notification messages sent to a topic 日本語訳:トピックに送信される通知メッセージでは、配信ステータスのログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-2 配信ステータスのログ記録 はCloudFormationでもサポートされておらず、CDKで実装するにはカスタムリソースで SDK 呼び出しをする必要があり( 参考 )、大変です。今後のアップデートに期待します。 SQS SQS.1 英語タイトル: Amazon SQS queues should be encrypted at rest 日本語訳: Amazon SQS キューは保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sqs-1 2022年10月より、新しく作成されるSQSキューは デフォルトで暗号化される ようになったため、特別な実装は不要になりました。 new sqs.Queue ( this , "Queue" , { // 指定しなくても新規作成されるキューはデフォルトで暗号化される encryption: sqs.QueueEncryption.SQS_MANAGED , } ); API Gateway APIGateway.1 英語タイトル: API Gateway REST and WebSocket API logging should be enabled 日本語訳: API Gateway REST および WebSocket API ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-1 CloudWatch Logs ロググループを作成し、 loggingLevel 、 accessLogDestination 、 accessLogFormat プロパティで ログの出力 を設定します。 const log = new logs.LogGroup ( this , "ApiGatewayLog" , { logGroupName: "api-gateway-log" , retention: logs.RetentionDays.SIX_MONTHS , } ); new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , loggingLevel: apigateway.MethodLoggingLevel.INFO , accessLogDestination: new apigateway.LogGroupLogDestination ( log ), accessLogFormat: apigateway.AccessLogFormat.clf (), } , } ); APIGateway.4 英語タイトル: API Gateway should be associated with an AWS WAF web ACL 日本語訳: API Gateway は、 AWS WAF ウェブ ACL に関連付けられている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-4 AWS WAFのWeb ACL を作成し、 API Gateway のステージに関連付けます。 コードを表示 const api = new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , } , } ); const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAcl" , { defaultAction: { allow: {} } , // scopeは REGIONAL とする scope: "REGIONAL" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "wafWebAcl" , } , rules: [ { // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); const webAclAssociation = new wafv2.CfnWebACLAssociation ( this , "WebAclAssociation" , { resourceArn: `arn:aws:apigateway: ${ region } ::/restapis/ ${ api4.restApiId } /stages/dev` , webAclArn: wafWebAcl.attrArn , } ); webAclAssociation.addDependsOn ( wafWebAcl ); webAclAssociation.addDependsOn ( api.deploymentStage.node.defaultChild as cdk.CfnResource ); APIGateway.5 英語タイトル: API Gateway REST API cache data should be encrypted at rest 日本語訳: API Gateway REST API のキャッシュデータは、保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-5 cachingEnabled を true にすることでこのルールの検出対象になり、 cacheDataEncrypted プロパティでキャッシュデータの暗号化を有効にできます。 new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , cachingEnabled: true , cacheDataEncrypted: true , } , } ); 大変長い記事になりました。読んでいただき、ありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
電通国際情報サービス Advent Calendar 2022 の12/13の記事です。 XI本部 オープン イノベーション ラボの飯田です。 今回は、ヘルスケア×ITっぽい領域の論文の紹介になります。 最近、デジタルヘルスやデジタルセラピューティクス(DTx)といった、デジタル技術で病気の予防や診断・治療を支援することがトレンドになってきています。 ISIDでも、 VR をつかった 幻肢痛 に対するセラピーや 錐体外路症状 (EPS)重症度判定など、ヘルスケア×ITの取り組みを進めています。 www.isid.co.jp www.isid.co.jp 業務インプットのために医療×ITの論文を調べていて、面白く・身近に感じられた論文を紹介します。 内容は「 ポケモンGO によってうつに効果があるのか?」です。 DISCLAIMER 記載内容の信頼性については可能な限り十分注意をしていますが、正確性・妥当性等を担保するものではありません。 該当論文の内容を参照しておりますが、医学的な内容も含んでおり、ご自身の判断にてご覧ください。一切の責任を負いかねますので、ご了承ください。 情報の誤りや不適切な表現があった場合には記事の編集・削除を行うこともございます。 論文情報・Abstract 研究のアイディア Google Trendsから地域のうつ傾向を推定する ポケモンGOの段階的リリースを利用し、統計的因果推論(DID)を行った ポケモンGO治療効果のモデリングとその結果 理論的背景・メカニズムについて まとめ 論文情報・Abstract Cheng, Z., Greenwood, B. N., & Pavlou, P. A. (2022). Location-based mobile gaming and local depression trends: a study of Pokémon Go. Journal of Management Information Systems , 39(1), 68-101. https://www.tandfonline.com/doi/full/10.1080/07421222.2021.2023407 位置情報ベースのモバイルゲー ム( ポケモンGO )が公衆衛生の大きな問題である うつ とどのような関連するかを統計的因果推論DIDを使って調べた論文です。 モデリング の結果、 ポケモンGO の導入が短期的にうつを減少させることを示唆しています。 研究のアイディア Google Trendsから地域のうつ傾向を推定する この研究では、地域のうつ傾向を捉えるために、 Google Trendsのデータを用いて うつ病 の地域傾向を推定しています。 先行研究を参考に、各地域の うつ病 関連の用語(例、depression、stressなど)に対する Google トレンドのデータを使用して、地域のうつ傾向を0から100のスケールで推定しています(100が最大・0は最低)。 2016年1月1日から12月12日までの50週間を対象に算出しています。 ポケモンGO の段階的リリースを利用し、統計的因果推論(DID)を行った Google Trendsから地域のうつ傾向を時系列で算出したのち、その時系列データに対してDIDを行い、 ポケモンGO の治療効果・介入効果を推定しています。 DIDとは、差分の差分分析(Difference-in-differences design)であり、統計的因果推論の手法の1つです。 RTCの実験ができない(介入を行ったグループのデータは取得可能だが、非介入グループとなるデータが得られない)場合に有効な手法です。 ※DIDについての詳細は、津川先生の解説ページ等をご覧ください 差分の差分分析(Difference-in-differences design) – 医療政策学×医療経済学 ポケモンGO は、2016年に 英語圏 の12カ国166地域に段階的にリリースされました。 リリースタイミングが時間的・地理的にずれているため、DIDの考え方に則り、 ポケモンGO の治療効果・介入効果を推定しています。 リリースされていない地域を” ポケモンGO の治療・介入を受けていない対象群”とみなし、 ポケモンGO リリース前後でのうつ傾向の変化を捉えます。そして、同時にリリースされていない地域のうつ傾向の変化を考慮することで、治療効果・介入効果を推定します。 ポケモンGO 治療効果の モデリング とその結果 ポケモンGO の処理の前後で週ごとに効果を観察・推定するために以下のような式で モデリング を行っています。 - yjt:t週目のj地域での地域のうつ傾向 - 本研究での従属変数 - γj :地域の固定効果 - λt:週の固定効果 - Pre-PokemonGo jt (k):地域j でのゲーム発売から介入前 t 週までの期間が k 週である場合に 1 に等しくなる指標 - ポケモンGOのリリース前の週をベースラインとするためn Pre-PokemonGo jt (−1)を0で正規化を行った - β1 :係数(β1が負であれば、ポケモンGOの導入がうつ減少を示す) - PokemonGo jt (k):t週の時点で地域jでゲームがリリースされているかどうかを示す(リリース済みであれば1、なければ0) - Post-PokemonGo:地域j でのゲーム発売から介入後 t 週までの期間が m 週である場合に 1 に等しくなる指標 - 推定は最小二乗法でおこなう その結果は以下のようになっています。 ポケモンGO 導入直後に、 β1の値を見ると、地域のうつ傾向が有意に減少していることが読みとれます。 そして、その効果は数週間持続していて、6週間ほどでこの効果は消失しています。 これは、 ポケモンGO の人気と連動しています(ピークが2ヶ月弱で、ゲームから離脱する人が多くいた)。 一方で、 ポケモンGO のリリースと、自殺関連の検索の間には相関がないそうです。 つまり、 ポケモンGO は、重度のうつには効果がない可能性が高いと考えられます。 まとめると、 ポケモンGO は軽度なうつに対して、短期的な効果があると示唆されました。 理論的背景・メ カニ ズムについて ポケモンGO がうつを減少させるメ カニ ズムとして、3つのメ カニ ズムが考えられるそうです。 プレーヤーの身体的活動の増加 別の研究では、 ポケモンGO のプレイヤーが1日に1,500歩程度、 身体活動 を増加させたことを報告しています。 身体的活動によって、精神衛生上の利点をもたらすと多くの医学研究が指摘しています。 ゲームプレイを通じてオフラインで社会的つながりを持つこと 人々が交流し、積極的に経験(ゲームのノウハウ等)を共有すると、その後ストレスや不安が減少するとされています。 屋外に出て自然と触れ合うこと 公園などの自然に触れるだけでも、反芻(はんすう:自分自身のネガティブな側面について繰り返し考えること)が減少し、 うつ病 を緩和するとされています。 ポケモン を捕まえるためには屋外を歩き、周囲を探索しなければならないため、 身体活動 が増加する。 ゲームをプレイする中で、交流することがあり、社会的つながりを持つことができる。 ゲームの主な機能( ポケストップ やポケジムなど)は、公園などの自然がある場所に多くあり、自然と触れ合うことができる。 この3つの条件・メ カニ ズムによって、うつが減少していると考えられます。 逆に、この上記3つのメ カニ ズムを持たないゲームを行った場合、逆のにうつが増加することも観察されたそうです。 まとめ 今回、 ポケモンGO はうつに効果があるという論文を紹介いたしました。 スマートシティに代表されるように、 IT技術 やサービスがより生活と密接するようになり、公衆衛生や市民の生活のためになる機会は今後増えていくと思います。 先端 IT技術 をうまく活用し、社会課題解決とビジネス両方で価値を出せるモノを作っていければと思っています。 私たちは同じグループで共に働いていただける仲間を募集しています。 ヘルスケア×ITのように、デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ソリューションアーキテクト スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
電通国際情報サービス Advent Calendar 2022 の12/13の記事です。 XI本部 オープン イノベーション ラボの飯田です。 今回は、ヘルスケア×ITっぽい領域の論文の紹介になります。 最近、デジタルヘルスやデジタルセラピューティクス(DTx)といった、デジタル技術で病気の予防や診断・治療を支援することがトレンドになってきています。 ISIDでも、 VR をつかった 幻肢痛 に対するセラピーや 錐体外路症状 (EPS)重症度判定など、ヘルスケア×ITの取り組みを進めています。 www.isid.co.jp www.isid.co.jp 業務インプットのために医療×ITの論文を調べていて、面白く・身近に感じられた論文を紹介します。 内容は「 ポケモンGO によってうつに効果があるのか?」です。 DISCLAIMER 記載内容の信頼性については可能な限り十分注意をしていますが、正確性・妥当性等を担保するものではありません。 該当論文の内容を参照しておりますが、医学的な内容も含んでおり、ご自身の判断にてご覧ください。一切の責任を負いかねますので、ご了承ください。 情報の誤りや不適切な表現があった場合には記事の編集・削除を行うこともございます。 論文情報・Abstract 研究のアイディア Google Trendsから地域のうつ傾向を推定する ポケモンGOの段階的リリースを利用し、統計的因果推論(DID)を行った ポケモンGO治療効果のモデリングとその結果 理論的背景・メカニズムについて まとめ 論文情報・Abstract Cheng, Z., Greenwood, B. N., & Pavlou, P. A. (2022). Location-based mobile gaming and local depression trends: a study of Pokémon Go. Journal of Management Information Systems , 39(1), 68-101. https://www.tandfonline.com/doi/full/10.1080/07421222.2021.2023407 位置情報ベースのモバイルゲー ム( ポケモンGO )が公衆衛生の大きな問題である うつ とどのような関連するかを統計的因果推論DIDを使って調べた論文です。 モデリング の結果、 ポケモンGO の導入が短期的にうつを減少させることを示唆しています。 研究のアイディア Google Trendsから地域のうつ傾向を推定する この研究では、地域のうつ傾向を捉えるために、 Google Trendsのデータを用いて うつ病 の地域傾向を推定しています。 先行研究を参考に、各地域の うつ病 関連の用語(例、depression、stressなど)に対する Google トレンドのデータを使用して、地域のうつ傾向を0から100のスケールで推定しています(100が最大・0は最低)。 2016年1月1日から12月12日までの50週間を対象に算出しています。 ポケモンGO の段階的リリースを利用し、統計的因果推論(DID)を行った Google Trendsから地域のうつ傾向を時系列で算出したのち、その時系列データに対してDIDを行い、 ポケモンGO の治療効果・介入効果を推定しています。 DIDとは、差分の差分分析(Difference-in-differences design)であり、統計的因果推論の手法の1つです。 RTCの実験ができない(介入を行ったグループのデータは取得可能だが、非介入グループとなるデータが得られない)場合に有効な手法です。 ※DIDについての詳細は、津川先生の解説ページ等をご覧ください 差分の差分分析(Difference-in-differences design) – 医療政策学×医療経済学 ポケモンGO は、2016年に 英語圏 の12カ国166地域に段階的にリリースされました。 リリースタイミングが時間的・地理的にずれているため、DIDの考え方に則り、 ポケモンGO の治療効果・介入効果を推定しています。 リリースされていない地域を” ポケモンGO の治療・介入を受けていない対象群”とみなし、 ポケモンGO リリース前後でのうつ傾向の変化を捉えます。そして、同時にリリースされていない地域のうつ傾向の変化を考慮することで、治療効果・介入効果を推定します。 ポケモンGO 治療効果の モデリング とその結果 ポケモンGO の処理の前後で週ごとに効果を観察・推定するために以下のような式で モデリング を行っています。 - yjt:t週目のj地域での地域のうつ傾向 - 本研究での従属変数 - γj :地域の固定効果 - λt:週の固定効果 - Pre-PokemonGo jt (k):地域j でのゲーム発売から介入前 t 週までの期間が k 週である場合に 1 に等しくなる指標 - ポケモンGOのリリース前の週をベースラインとするためn Pre-PokemonGo jt (−1)を0で正規化を行った - β1 :係数(β1が負であれば、ポケモンGOの導入がうつ減少を示す) - PokemonGo jt (k):t週の時点で地域jでゲームがリリースされているかどうかを示す(リリース済みであれば1、なければ0) - Post-PokemonGo:地域j でのゲーム発売から介入後 t 週までの期間が m 週である場合に 1 に等しくなる指標 - 推定は最小二乗法でおこなう その結果は以下のようになっています。 ポケモンGO 導入直後に、 β1の値を見ると、地域のうつ傾向が有意に減少していることが読みとれます。 そして、その効果は数週間持続していて、6週間ほどでこの効果は消失しています。 これは、 ポケモンGO の人気と連動しています(ピークが2ヶ月弱で、ゲームから離脱する人が多くいた)。 一方で、 ポケモンGO のリリースと、自殺関連の検索の間には相関がないそうです。 つまり、 ポケモンGO は、重度のうつには効果がない可能性が高いと考えられます。 まとめると、 ポケモンGO は軽度なうつに対して、短期的な効果があると示唆されました。 理論的背景・メ カニ ズムについて ポケモンGO がうつを減少させるメ カニ ズムとして、3つのメ カニ ズムが考えられるそうです。 プレーヤーの身体的活動の増加 別の研究では、 ポケモンGO のプレイヤーが1日に1,500歩程度、 身体活動 を増加させたことを報告しています。 身体的活動によって、精神衛生上の利点をもたらすと多くの医学研究が指摘しています。 ゲームプレイを通じてオフラインで社会的つながりを持つこと 人々が交流し、積極的に経験(ゲームのノウハウ等)を共有すると、その後ストレスや不安が減少するとされています。 屋外に出て自然と触れ合うこと 公園などの自然に触れるだけでも、反芻(はんすう:自分自身のネガティブな側面について繰り返し考えること)が減少し、 うつ病 を緩和するとされています。 ポケモン を捕まえるためには屋外を歩き、周囲を探索しなければならないため、 身体活動 が増加する。 ゲームをプレイする中で、交流することがあり、社会的つながりを持つことができる。 ゲームの主な機能( ポケストップ やポケジムなど)は、公園などの自然がある場所に多くあり、自然と触れ合うことができる。 この3つの条件・メ カニ ズムによって、うつが減少していると考えられます。 逆に、この上記3つのメ カニ ズムを持たないゲームを行った場合、逆のにうつが増加することも観察されたそうです。 まとめ 今回、 ポケモンGO はうつに効果があるという論文を紹介いたしました。 スマートシティに代表されるように、 IT技術 やサービスがより生活と密接するようになり、公衆衛生や市民の生活のためになる機会は今後増えていくと思います。 先端 IT技術 をうまく活用し、社会課題解決とビジネス両方で価値を出せるモノを作っていければと思っています。 私たちは同じグループで共に働いていただける仲間を募集しています。 ヘルスケア×ITのように、デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ソリューションアーキテクト スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは、ISID 金融ソリューション事業部の若本です。 本記事は 電通国際情報サービス Advent Calendar 2022 の12日目の記事となります!前日の記事は徳山さんの「フロントエンド開発にちょっと慣れてきた方におすすめしたいPatterns.dev」でした。 この記事では、今年発表されたAIモデルである「nvdiffrec」を使って、 iPhone で撮影した動画から3Dモデルを作成する手順 をご紹介します。 今回作成したのは、上記画像の「青い遊具」になります! はじめに 近年、NeRFをはじめとして リアルの物体や景色を3Dに落とし込む技術 が盛り上がりを見せています。 先日の記事 でもNeRFから3Dのシーンを生成しました。3Dの視点がサクッと生成できるのはすごいですよね。 上記のようなNeRFの結果は、そのまま3Dアプリケーションで使えるものでしょうか?現在、 答えは「No」 です。 NeRFの出力は「輝度場」と呼ばれるものであり、カメラから見える光の反射を推定して出力しています。一方、 Blender をはじめとする3DCG制作エンジンでは、メッシュなどを取り込むのが一般的です。メッシュは形状として落とし込まれたデータになっており、NeRFのように曖昧な箇所をぼかした表現はできません。 そのため、既存の3DCG制作エンジンにNeRFの結果を取り込むには、一工夫が必要になります。 たとえば、先日ご紹介したInstant NGP 1 では、Instant NeRFの出力から古典的な手法を用いてメッシュ化する試験的な機能が備わっています。この機能を使うと、下記のような結果が得られます。 大枠はNeRFの結果と変わりませんが、印象がかなり異なるかと思います。出力されたメッシュの凹凸が激しく、メッシュについている色がfloater(周りに浮いている雲のようなもの)の色になっていたり、元の画像と全く異なる結果となっています。NeRFではうまくぼかせていたものを無理やりメッシュにしたために 見た目の印象がかなり変わってしまいます 。 そこで今回は、3Dメッシュを直接生成するAIモデルを検証することにしました。 nvdiffrecとは? nvdiffrec 2 は、 3Dメッシュを直接生成するAIモデル です。 NeRF同様、 nvidia が開発したAIモデルであり、画像処理のトップカンファレンスであるCVPR2022にも採択されています。 nvdiffrecでは上記の課題に対し、3DCG制作エンジンに直接取り込めるアウトプットを直接学習します。このとき、形状・素材・照明環境をそれぞれ最適化することによって、画像の見え方から「対象の素材や画像内の照明環境」を推定できます。下記はnvdiffrecの公式の紹介動画になります。 結果として、上記動画内のように元の形状や色に近い3Dメッシュが出力されます。 自分で撮影した動画でnvdiffrecを動かす方法 本記事では、 nvdiffrecのリポジトリ を用いて、 自分で撮影した動画から3Dメッシュを作成する手順 をご紹介します。 なお、本記事で使用するコードは こちら に配置しています。 基本的にはポチポチ「Shift+Enter」を押すだけで動くようになっております のでご活用ください。 0. 事前準備 Instant NGP の実行環境(別環境) Google drive の準備 実行コード のダウンロードと Google drive への配置 ※撮影機材はiPhone11、縦動画撮影での動作を確認済みです。 1. 動画を撮影 (可能であれば)360度から対象物を撮影しましょう。カメラの位置情報を推定するため、対象物は動かさないほうがよいです。この際、筆者は 物体が見切れないように撮影を行いました 。 撮影の基本的なコツは 以前の記事 を参考にしていただけると幸いです。 ここでは、対象物を2周する形で計20秒間の動画撮影を行っています。筆者はiPhone11で撮影したため、解像度は1920×1080です。リソースの都合上、後段の処理で512pixelまで解像度を落とすため、512pixel以上の解像度であれば問題はありません。 また、必須ではありませんが、撮影後に一度NeRFで出力してみることをおすすめします。NeRFがうまく出力できていない場合、以降のプロセスでの結果が期待できなくなります。 2. Google Drive 上で画像に変換 撮影した動画を Google Drive にアップし、 こちらのコード で画像に変換します。 Google Colaboratory(以下Colabと呼称)上でコードを開くと下記のような画面が現れますので、ファイル名を設定して実行します。 下記のように「<フォルダ名>/images/<切り出した画像名>」のフォルダ階層になっていれば方法は特に問いません。 3. カメラ情報の推定&物体のマスク推定(ローカル環境) nvdiffrecを動作させる前に、以下の情報が必要になります。 imagesと同じ階層に「masks」フォルダを配置し、その中に「images」内の画像に対応したマスク画像 imagesと同じ階層にカメラ位置の推定情報(pose_bounds.npy) 今回のコードにはその処理を含めていないため、別の環境で用意することにします。 筆者は、nvdiffrec内の issue を参考に、有志の方が作成されている colmap2poses.py を使用しました(2022年11月時点で公式からカスタムデー タセット への適用手順は示されていません)。Instant NeRFが動作する環境であれば、 rembg を追加でインストールするだけで動作します。 pip install rembg 「images」が入ったフォルダとこの スクリプト をInstant NeRFが動作する環境に配置し、下記のコマンドで動かしました。 python colmap2poses.py --mask "imagesを含むフォルダへのpath" --colmap_path "colmapのpath" 上記の スクリプト では、カメラ位置の推定をcolmapを用いて行うとともに、AIモデル「U 2Net 3 」を用いた物体の切り抜きを行っています。 実行後、下記のようなフォルダ構成になっていればOKです。 ただし、「masks」に格納されているマスク画像はrembgで自動推定されたものですので、影が予測結果に入ってしまったり、予測結果が欠けていたりしています。 そこで、筆者はより精度を高めるために、 アノテーション ツール「 EISeg 4 」を用いて直接マスク画像の作成を行いました。 600枚弱の画像があったため、4時間ほどかけて アノテーション を行いました。手間がかかるため、少しでも良い結果を得たい場合のみおすすめします。 4. nvdiffrecの実行 3.の結果を Google Drive にアップし、 こちらのコード に沿ってColab上でnvdiffrecを学習させます。学習の手順は下記の通りです。 ①:関連ライブラリをインストールする ②:前処理を行う ③:nvdiffrecのパラメータを設定して実行する それぞれについて、簡単に見てみましょう。 4-①:関連ライブラリをインストールする Google drive を同期した後、関連ライブラリをインストールします。 初回のみ、nvdiffrecを Google drive 上にcloneする必要があります。下記はColab上で コード を開いた画面です。cloneしていない場合のみ、「nvdiffrec_install」のチェックが必要になります。 4-②:前処理を行う こちらは コード の下記3つのセルを順番に実行すると完了します。 上図内のコードでは、基本的にcroppingとscalingの2つの処理を行いました。 croppingでは、学習しやすいように正方形の画像をもとの画像から切り出しています。本来であれば、画像をそのままモデルに入れることが望ましいですが、今回は時間の都合上断念しました。さらに、見切れている画像を学習に使わない処理も事前に実施しています。 scalingでは、学習に用いる画像のリサイズを行いました。筆者は512pixelで動作確認しましたが、こちらを大きくするほど高い品質が見込めるため、リソースに余裕のある方は大きくすることを推奨します。なお、scalingのコードはnvdiffrec/data/derd/scale_images.pyとほぼ同様です。 4-③:nvdiffrecのパラメータを設定して実行する 最後に、パラメータを設定して実行してみましょう。colab上ではいくつか GUI で設定できるようにしてありますが、それ以外の設定項目もありますので、適宜nvdiffrecの リポジトリ をご確認ください。 !python train.py --config $config_path 上記のコードを実行すると、nvdiffrecの学習が開始されます。学習が完了すると、nvdiffrec/out下に.obj形式、.mtl形式のメッシュとテクス チャフ ァイルが生成されます。 今回使用したデータでは、下記のような結果が得られました。 光の反射が特殊だった上部については推定がうまくいきませんでしたが、それらしきメッシュは作成することができました ! 形状と色が改善できており、そのままNeRFでメッシュを出力するよりも良い結果が得られているといえそうです。メッシュの出力は、マシンスペックやデータ量の増加、チューニングの工夫によってさらに改善することが見込めます。 最終的に、作成したメッシュは、 もちろん Blender などで取り込むことができます ! せっかくの アドベントカレンダー なので、クリスマス仕様にしてみました! おわりに この記事ではnvdiffrecを用いて、 iPhone で撮影した動画から3Dメッシュを作成する手順についてご紹介しました。 3DCG技術に関するAIの発展は目覚ましく、実用的な3DモデルをAIで手軽に生成する未来は着実に近づいていると感じています。ワクワクするような技術が次々と現れる今日ですが、引き続き楽しんでキャッチアップしていきたいと思います。 最後までお読みいただき、ありがとうございました。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました ) NVIDIA Instant NeRF NGP ↩ Extracting Triangular 3D Models, Materials, and Lighting From Images ↩ U 2 -Net: Going Deeper with Nested U-Structure for Salient Object Detection ↩ EISeg: An Efficient Interactive Segmentation Tool based on PaddlePaddle ↩
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、Stable Diffusion 2.1- 美少女アニメ 画です。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文 美少女アニメ画 美少女写真 女性イラスト 長い呪文は切り捨てられる AUTOMATIC1111のインストール AUTOMATIC1111のセッティング 美少女アニメ画の呪文 通常呪文の解説 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows ネガティブ呪文の解説 deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 手が変になる問題は改善されたのか まとめ 仲間募集 Stable Diffusionの全コンテンツ AUTOMATIC1111のインストール Stable Diffusion 2.1 を実行する環境として、 AUTOMATIC1111 を使います。 AUTOMATIC1111 は、 Stable Diffusion を Google Colab 直接ではなく、 UI 経由で実行できるようにしています。似たような機能のものはいくつかありますが、 AUTOMATIC1111 は人気が高く、情報量も多いのでおすすめです。 Google Colab で動かすための公式のノートブックは こちら になります。 このノートブックを実行すると、下の方に Running on public URL: https://2c76db068be0e79a.gradio.app のようなリンクが表示されるので、クリックしましょう。 AUTOMATIC1111のセッティング パラメータは以下のようになります。 Sampling Steps: 50 Sampling Method: DPM2 Width: 768 Height: 768 CFG Scale: 7.5 Seed: -1 Sampling Stepsは、デフォルトの 20 だと少ないので、 50 くらいにしておきましょう。 Sampling Methodは DPM2 をお勧めしますが、 DDIM も悪くはありません。 Width と Height は 768 をお勧めします。今回使っているモデルは、 768 用のためです。 512 だとかを使うと画像が崩れることがあります。 CFG Scale は入力した呪文にどれだけ近い画像を生成するかのパラメータです。デフォルトの 7 でも問題ありませんが、僕はなんとなく 7.5 を指定しています。 美少女アニメ 画の呪文 それでは、 美少女アニメ 画の呪文(prompt)を紹介します。今回から、ネガティブ呪文も合わせて紹介します。ネガティブ呪文とは通常呪文を打ち消す呪文です。 例えば、ネガティブ呪文に mutated hands を指定すると、 変異した手 が出力されにくくなります。 通常呪文は次のようになります。 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows 通常呪文の改行版は次のようになります。 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows ネガティブ呪文は次のようになります。 deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white ネガティブ呪文の改行版は次のようになります。 deformed mutated lowres blurred disfigured repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 出力結果の例です。 通常呪文の解説 それでは、通常呪文を解説しましょう。 masterpiece masterpiece は、「傑作」、「名作」、「定番」の意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。「気がします」というのは、「確信はないけど経験上は、そのように感じる」という意味です。 high quality high quality は、「高品質」の意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。 highly detailed highly detailed は、「とても詳細に描画する」という意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。 ( kawaii princess:1.2) kawaii princess が今回の描画対象です。 beautiful girl よりも kawaii princess の方が、美少女率が高くなる気がします。 (呪文:数値) は、呪文を強調する AUTOMAIC1111 の構文です。数値が 1.0 は強調なしで、 呪文 と全く同じになります。数値が 1.0 より大きいと強調され、 1.0 より低いと弱められます。 white glowing skin white glowing skin は、「白く輝く肌」という意味です。 ( kawaii face with blush:1.2) kawaii face with blush は、「ほほがちょっと赤い可愛い顔」という意味です。 beautiful face より kawaii face の方が、美少女率が高くなる気がします。 通常より強調(1.2)しています。好みで数値を調整してください。 blue eyes with eyelashes blue eyes with eyelashes は、「まつげのある青い目」という意味です。 blue の部分は好きな色に変えてください。 long waved hair long waved hair は、「長いウェーブのかかった髪」という意味です。好みで、色を足したり、 waved を straight に変えてください。 (cleavage breasts:1.1) cleavage breasts は、「胸の谷間」という意味です。通常より強調(1.1)しています。好みで数値を調整してください。 open shoulders open shoulders は、「肩が露出している」という意味です。 gothic lolita glossy dress with ruffles gothic lolita glossy dress with ruffles は、「フリル付きの光沢のあるゴシックロリータドレス」という意味です。 gorgeous jewelry accessories gorgeous jewelry accessories は、「ゴージャスな宝石のついたアクセサリー」という意味です。 (anime:1.3) anime を指定することで、アニメ画になります。アニメっぽくなるように少し強調(1.3)しています。 artstation artstation は、イラストの投稿サイトです。指定するとイラストのクオリティが上がります。 gorgeous background gorgeous background を指定して、背景を「ゴージャス」にします。「ゴージャス」というのはアバウトに感じるかもしれませんが、この指定でいい感じの背景になることが多いです。 centered composition centered composition を指定して、描画対象を中心に持ってきます。 lim lighting lim lighting を指定して、モデルの後方からライトをあて、モデルの輪郭がうっすら明るくなるようにします。 intense shadows intense shadows は、「強い影」という意味です。影が強調されることで、メリハリの付いた画像になります。 ネガティブ呪文の解説 次は、ネガティブ呪文を解説します。ネガティブ呪文とは、通常呪文を打ち消す呪文です。 deformed mutated disfigured deformed 、 mutated 、 disfigured は、「変形した」を打ち消します。 lowres lowres は、「低い解像度」を打ち消します。 blurred blurred は、「ぼやけた」を打ち消します。 repetitive repetitive は、「繰り返し」を打ち消します。体のパーツなどが余分に複製されることを防ぎます。 double double は、「二重」を打ち消します。体のパーツなどが余分に複製されることを防ぎます。 mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands hands (手)は、最も変になりやすい部位のひとつなので、 mutated (変異した)、 bad (ダメな)、 missing (存在しない)、 extra (余分な)、 liquid (液状の)、 poorly drawn (下手に描かれた)を指定して、念入りに打ち消します。 mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers fingers (指)も、最も変になりやすい部位のひとつなので、手と同様に念入りに打ち消します。 partial head partial head で、「部分的な頭」を打ち消します。頭の一部が欠けることを防ぎます。 bad face small face partial face bad face で、「ダメな顔」を打ち消します。 small face で、「小さい顔」を打ち消します。人物が小さくなりすぎるのを防ぎます。 partial face で、「部分的な顔」を打ち消します。顔の一部が欠けることを防ぎます。 bad eyes too big eyes bad eyes で、「だめな目」を打ち消します。 too big eyes で、目が大きくなりすぎるのを防ぎます。 bad eyebrows bad eyebrows で、「ダメなまゆげ」を打ち消します。 bad eyelashes bad eyelashes で、「ダメなまつげ」を打ち消します。 bad nose missing nose nose (鼻)は、消えてしまうことがあるので、 missing (存在しない)で打ち消します。 bad mouth missing mouth open mouth mouth (口)は、消えてしまうことがあるので、 missing (存在しない)で打ち消します。 open mouth で、口がぽかんと開くのを防ぎます。 bad ears bad ears で、「ダメな耳」を打ち消します。 thick lips thick lips で、「厚い唇」を打ち消します。 chest pad 通常呪文で cleavage breasts (胸の谷間)を指定すると、ときどき、胸パッドが出力されることがあります。これを chest pad (胸パッド)で打ち消します。 bad legs missing legs extra legs legs (脚)は、ときどき消えたり、余分な足が生えたりするので、 missing (存在しない)、 extra (余分な)で打ち消します。 bad arms missing arms extra arms arms (腕)は、ときどき消えたり、余分な腕が生えたりするので、 missing (存在しない)、 extra (余分な)で打ち消します。 low quality normal quality low quality (低いクオリティ)、 normal quality (普通のクオリティ)を打ち消します。その結果、 high quality (高いクオリティ)の画像になります。 crown 描画対象が、 princess なので、王冠をかぶる確率が増えます。王冠がいらない場合は、 crown で打ち消します。 black and white black and white (白黒)を指定して、モノクロ画像になってしまうのを防ぎます。 手が変になる問題は改善されたのか Stable Diffusion 2.1 は、「手/指が変になる問題」が改善されていると公式が発表しているので、検証してみました。 僕の試した結果では、手が指までちゃんと描画されるのは、手が描画されるケースで、20回に1回あるかないかです。今後のアップデートに期待ですね。 まとめ 今回は、 美少女アニメ 画の呪文を紹介しました。 かなり高確率でクオリティの高い画像が出力されるので、みなさんもぜひ試してください。 次回は、- v2.1 金髪美女写真 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、Stable Diffusion 2.1- 美少女アニメ 画です。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文 美少女アニメ画 美少女写真 女性イラスト 長い呪文は切り捨てられる AUTOMATIC1111のインストール AUTOMATIC1111のセッティング 美少女アニメ画の呪文 通常呪文の解説 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows ネガティブ呪文の解説 deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 手が変になる問題は改善されたのか まとめ 仲間募集 Stable Diffusionの全コンテンツ AUTOMATIC1111のインストール Stable Diffusion 2.1 を実行する環境として、 AUTOMATIC1111 を使います。 AUTOMATIC1111 は、 Stable Diffusion を Google Colab 直接ではなく、 UI 経由で実行できるようにしています。似たような機能のものはいくつかありますが、 AUTOMATIC1111 は人気が高く、情報量も多いのでおすすめです。 Google Colab で動かすための公式のノートブックは こちら になります。 このノートブックを実行すると、下の方に Running on public URL: https://2c76db068be0e79a.gradio.app のようなリンクが表示されるので、クリックしましょう。 AUTOMATIC1111のセッティング パラメータは以下のようになります。 Sampling Steps: 50 Sampling Method: DPM2 Width: 768 Height: 768 CFG Scale: 7.5 Seed: -1 Sampling Stepsは、デフォルトの 20 だと少ないので、 50 くらいにしておきましょう。 Sampling Methodは DPM2 をお勧めしますが、 DDIM も悪くはありません。 Width と Height は 768 をお勧めします。今回使っているモデルは、 768 用のためです。 512 だとかを使うと画像が崩れることがあります。 CFG Scale は入力した呪文にどれだけ近い画像を生成するかのパラメータです。デフォルトの 7 でも問題ありませんが、僕はなんとなく 7.5 を指定しています。 美少女アニメ 画の呪文 それでは、 美少女アニメ 画の呪文(prompt)を紹介します。今回から、ネガティブ呪文も合わせて紹介します。ネガティブ呪文とは通常呪文を打ち消す呪文です。 例えば、ネガティブ呪文に mutated hands を指定すると、 変異した手 が出力されにくくなります。 通常呪文は次のようになります。 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows 通常呪文の改行版は次のようになります。 masterpiece high quality highly detailed (kawaii princess:1.2) white glowing skin (kawaii face with blush:1.2) blue eyes with eyelashes long waved hair (cleavage breasts:1.1) open shoulders gothic lolita glossy dress with ruffles gorgeous jewelry accessories (anime:1.3) artstation gorgeous background centered composition lim lighting intense shadows ネガティブ呪文は次のようになります。 deformed mutated disfigured lowres blurred repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white ネガティブ呪文の改行版は次のようになります。 deformed mutated lowres blurred disfigured repetitive double mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers partial head bad face small face partial face bad eyes too big eyes bad eyebrows bad eyelashes bad nose missing nose bad mouth missing mouth open mouth bad ears thick lips chest pad bad legs missing legs extra legs bad arms missing arms extra arms low quality normal quality crown black and white 出力結果の例です。 通常呪文の解説 それでは、通常呪文を解説しましょう。 masterpiece masterpiece は、「傑作」、「名作」、「定番」の意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。「気がします」というのは、「確信はないけど経験上は、そのように感じる」という意味です。 high quality high quality は、「高品質」の意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。 highly detailed highly detailed は、「とても詳細に描画する」という意味で、これを初めの方に持ってくると画像のクオリティが上がる気がします。 ( kawaii princess:1.2) kawaii princess が今回の描画対象です。 beautiful girl よりも kawaii princess の方が、美少女率が高くなる気がします。 (呪文:数値) は、呪文を強調する AUTOMAIC1111 の構文です。数値が 1.0 は強調なしで、 呪文 と全く同じになります。数値が 1.0 より大きいと強調され、 1.0 より低いと弱められます。 white glowing skin white glowing skin は、「白く輝く肌」という意味です。 ( kawaii face with blush:1.2) kawaii face with blush は、「ほほがちょっと赤い可愛い顔」という意味です。 beautiful face より kawaii face の方が、美少女率が高くなる気がします。 通常より強調(1.2)しています。好みで数値を調整してください。 blue eyes with eyelashes blue eyes with eyelashes は、「まつげのある青い目」という意味です。 blue の部分は好きな色に変えてください。 long waved hair long waved hair は、「長いウェーブのかかった髪」という意味です。好みで、色を足したり、 waved を straight に変えてください。 (cleavage breasts:1.1) cleavage breasts は、「胸の谷間」という意味です。通常より強調(1.1)しています。好みで数値を調整してください。 open shoulders open shoulders は、「肩が露出している」という意味です。 gothic lolita glossy dress with ruffles gothic lolita glossy dress with ruffles は、「フリル付きの光沢のあるゴシックロリータドレス」という意味です。 gorgeous jewelry accessories gorgeous jewelry accessories は、「ゴージャスな宝石のついたアクセサリー」という意味です。 (anime:1.3) anime を指定することで、アニメ画になります。アニメっぽくなるように少し強調(1.3)しています。 artstation artstation は、イラストの投稿サイトです。指定するとイラストのクオリティが上がります。 gorgeous background gorgeous background を指定して、背景を「ゴージャス」にします。「ゴージャス」というのはアバウトに感じるかもしれませんが、この指定でいい感じの背景になることが多いです。 centered composition centered composition を指定して、描画対象を中心に持ってきます。 lim lighting lim lighting を指定して、モデルの後方からライトをあて、モデルの輪郭がうっすら明るくなるようにします。 intense shadows intense shadows は、「強い影」という意味です。影が強調されることで、メリハリの付いた画像になります。 ネガティブ呪文の解説 次は、ネガティブ呪文を解説します。ネガティブ呪文とは、通常呪文を打ち消す呪文です。 deformed mutated disfigured deformed 、 mutated 、 disfigured は、「変形した」を打ち消します。 lowres lowres は、「低い解像度」を打ち消します。 blurred blurred は、「ぼやけた」を打ち消します。 repetitive repetitive は、「繰り返し」を打ち消します。体のパーツなどが余分に複製されることを防ぎます。 double double は、「二重」を打ち消します。体のパーツなどが余分に複製されることを防ぎます。 mutated hands bad hands missing hands extra hands liquid hands poorly drawn hands hands (手)は、最も変になりやすい部位のひとつなので、 mutated (変異した)、 bad (ダメな)、 missing (存在しない)、 extra (余分な)、 liquid (液状の)、 poorly drawn (下手に描かれた)を指定して、念入りに打ち消します。 mutated fingers bad fingers missing fingers extra fingers liquid fingers poorly drawn fingers fingers (指)も、最も変になりやすい部位のひとつなので、手と同様に念入りに打ち消します。 partial head partial head で、「部分的な頭」を打ち消します。頭の一部が欠けることを防ぎます。 bad face small face partial face bad face で、「ダメな顔」を打ち消します。 small face で、「小さい顔」を打ち消します。人物が小さくなりすぎるのを防ぎます。 partial face で、「部分的な顔」を打ち消します。顔の一部が欠けることを防ぎます。 bad eyes too big eyes bad eyes で、「だめな目」を打ち消します。 too big eyes で、目が大きくなりすぎるのを防ぎます。 bad eyebrows bad eyebrows で、「ダメなまゆげ」を打ち消します。 bad eyelashes bad eyelashes で、「ダメなまつげ」を打ち消します。 bad nose missing nose nose (鼻)は、消えてしまうことがあるので、 missing (存在しない)で打ち消します。 bad mouth missing mouth open mouth mouth (口)は、消えてしまうことがあるので、 missing (存在しない)で打ち消します。 open mouth で、口がぽかんと開くのを防ぎます。 bad ears bad ears で、「ダメな耳」を打ち消します。 thick lips thick lips で、「厚い唇」を打ち消します。 chest pad 通常呪文で cleavage breasts (胸の谷間)を指定すると、ときどき、胸パッドが出力されることがあります。これを chest pad (胸パッド)で打ち消します。 bad legs missing legs extra legs legs (脚)は、ときどき消えたり、余分な足が生えたりするので、 missing (存在しない)、 extra (余分な)で打ち消します。 bad arms missing arms extra arms arms (腕)は、ときどき消えたり、余分な腕が生えたりするので、 missing (存在しない)、 extra (余分な)で打ち消します。 low quality normal quality low quality (低いクオリティ)、 normal quality (普通のクオリティ)を打ち消します。その結果、 high quality (高いクオリティ)の画像になります。 crown 描画対象が、 princess なので、王冠をかぶる確率が増えます。王冠がいらない場合は、 crown で打ち消します。 black and white black and white (白黒)を指定して、モノクロ画像になってしまうのを防ぎます。 手が変になる問題は改善されたのか Stable Diffusion 2.1 は、「手/指が変になる問題」が改善されていると公式が発表しているので、検証してみました。 僕の試した結果では、手が指までちゃんと描画されるのは、手が描画されるケースで、20回に1回あるかないかです。今後のアップデートに期待ですね。 まとめ 今回は、 美少女アニメ 画の呪文を紹介しました。 かなり高確率でクオリティの高い画像が出力されるので、みなさんもぜひ試してください。 次回は、- v2.1 金髪美女写真 です。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
こんにちは、ISID 金融ソリューション事業部の若本です。 本記事は 電通国際情報サービス Advent Calendar 2022 の12日目の記事となります!前日の記事は徳山さんの「フロントエンド開発にちょっと慣れてきた方におすすめしたいPatterns.dev」でした。 この記事では、今年発表されたAIモデルである「nvdiffrec」を使って、 iPhone で撮影した動画から3Dモデルを作成する手順 をご紹介します。 今回作成したのは、上記画像の「青い遊具」になります! はじめに 近年、NeRFをはじめとして リアルの物体や景色を3Dに落とし込む技術 が盛り上がりを見せています。 先日の記事 でもNeRFから3Dのシーンを生成しました。3Dの視点がサクッと生成できるのはすごいですよね。 上記のようなNeRFの結果は、そのまま3Dアプリケーションで使えるものでしょうか?現在、 答えは「No」 です。 NeRFの出力は「輝度場」と呼ばれるものであり、カメラから見える光の反射を推定して出力しています。一方、 Blender をはじめとする3DCG制作エンジンでは、メッシュなどを取り込むのが一般的です。メッシュは形状として落とし込まれたデータになっており、NeRFのように曖昧な箇所をぼかした表現はできません。 そのため、既存の3DCG制作エンジンにNeRFの結果を取り込むには、一工夫が必要になります。 たとえば、先日ご紹介したInstant NGP 1 では、Instant NeRFの出力から古典的な手法を用いてメッシュ化する試験的な機能が備わっています。この機能を使うと、下記のような結果が得られます。 大枠はNeRFの結果と変わりませんが、印象がかなり異なるかと思います。出力されたメッシュの凹凸が激しく、メッシュについている色がfloater(周りに浮いている雲のようなもの)の色になっていたり、元の画像と全く異なる結果となっています。NeRFではうまくぼかせていたものを無理やりメッシュにしたために 見た目の印象がかなり変わってしまいます 。 そこで今回は、3Dメッシュを直接生成するAIモデルを検証することにしました。 nvdiffrecとは? nvdiffrec 2 は、 3Dメッシュを直接生成するAIモデル です。 NeRF同様、 nvidia が開発したAIモデルであり、画像処理のトップカンファレンスであるCVPR2022にも採択されています。 nvdiffrecでは上記の課題に対し、3DCG制作エンジンに直接取り込めるアウトプットを直接学習します。このとき、形状・素材・照明環境をそれぞれ最適化することによって、画像の見え方から「対象の素材や画像内の照明環境」を推定できます。下記はnvdiffrecの公式の紹介動画になります。 結果として、上記動画内のように元の形状や色に近い3Dメッシュが出力されます。 自分で撮影した動画でnvdiffrecを動かす方法 本記事では、 nvdiffrecのリポジトリ を用いて、 自分で撮影した動画から3Dメッシュを作成する手順 をご紹介します。 なお、本記事で使用するコードは こちら に配置しています。 基本的にはポチポチ「Shift+Enter」を押すだけで動くようになっております のでご活用ください。 0. 事前準備 Instant NGP の実行環境(別環境) Google drive の準備 実行コード のダウンロードと Google drive への配置 ※撮影機材はiPhone11、縦動画撮影での動作を確認済みです。 1. 動画を撮影 (可能であれば)360度から対象物を撮影しましょう。カメラの位置情報を推定するため、対象物は動かさないほうがよいです。この際、筆者は 物体が見切れないように撮影を行いました 。 撮影の基本的なコツは 以前の記事 を参考にしていただけると幸いです。 ここでは、対象物を2周する形で計20秒間の動画撮影を行っています。筆者はiPhone11で撮影したため、解像度は1920×1080です。リソースの都合上、後段の処理で512pixelまで解像度を落とすため、512pixel以上の解像度であれば問題はありません。 また、必須ではありませんが、撮影後に一度NeRFで出力してみることをおすすめします。NeRFがうまく出力できていない場合、以降のプロセスでの結果が期待できなくなります。 2. Google Drive 上で画像に変換 撮影した動画を Google Drive にアップし、 こちらのコード で画像に変換します。 Google Colaboratory(以下Colabと呼称)上でコードを開くと下記のような画面が現れますので、ファイル名を設定して実行します。 下記のように「<フォルダ名>/images/<切り出した画像名>」のフォルダ階層になっていれば方法は特に問いません。 3. カメラ情報の推定&物体のマスク推定(ローカル環境) nvdiffrecを動作させる前に、以下の情報が必要になります。 imagesと同じ階層に「masks」フォルダを配置し、その中に「images」内の画像に対応したマスク画像 imagesと同じ階層にカメラ位置の推定情報(pose_bounds.npy) 今回のコードにはその処理を含めていないため、別の環境で用意することにします。 筆者は、nvdiffrec内の issue を参考に、有志の方が作成されている colmap2poses.py を使用しました(2022年11月時点で公式からカスタムデー タセット への適用手順は示されていません)。Instant NeRFが動作する環境であれば、 rembg を追加でインストールするだけで動作します。 pip install rembg 「images」が入ったフォルダとこの スクリプト をInstant NeRFが動作する環境に配置し、下記のコマンドで動かしました。 python colmap2poses.py --mask "imagesを含むフォルダへのpath" --colmap_path "colmapのpath" 上記の スクリプト では、カメラ位置の推定をcolmapを用いて行うとともに、AIモデル「U 2Net 3 」を用いた物体の切り抜きを行っています。 実行後、下記のようなフォルダ構成になっていればOKです。 ただし、「masks」に格納されているマスク画像はrembgで自動推定されたものですので、影が予測結果に入ってしまったり、予測結果が欠けていたりしています。 そこで、筆者はより精度を高めるために、 アノテーション ツール「 EISeg 4 」を用いて直接マスク画像の作成を行いました。 600枚弱の画像があったため、4時間ほどかけて アノテーション を行いました。手間がかかるため、少しでも良い結果を得たい場合のみおすすめします。 4. nvdiffrecの実行 3.の結果を Google Drive にアップし、 こちらのコード に沿ってColab上でnvdiffrecを学習させます。学習の手順は下記の通りです。 ①:関連ライブラリをインストールする ②:前処理を行う ③:nvdiffrecのパラメータを設定して実行する それぞれについて、簡単に見てみましょう。 4-①:関連ライブラリをインストールする Google drive を同期した後、関連ライブラリをインストールします。 初回のみ、nvdiffrecを Google drive 上にcloneする必要があります。下記はColab上で コード を開いた画面です。cloneしていない場合のみ、「nvdiffrec_install」のチェックが必要になります。 4-②:前処理を行う こちらは コード の下記3つのセルを順番に実行すると完了します。 上図内のコードでは、基本的にcroppingとscalingの2つの処理を行いました。 croppingでは、学習しやすいように正方形の画像をもとの画像から切り出しています。本来であれば、画像をそのままモデルに入れることが望ましいですが、今回は時間の都合上断念しました。さらに、見切れている画像を学習に使わない処理も事前に実施しています。 scalingでは、学習に用いる画像のリサイズを行いました。筆者は512pixelで動作確認しましたが、こちらを大きくするほど高い品質が見込めるため、リソースに余裕のある方は大きくすることを推奨します。なお、scalingのコードはnvdiffrec/data/derd/scale_images.pyとほぼ同様です。 4-③:nvdiffrecのパラメータを設定して実行する 最後に、パラメータを設定して実行してみましょう。colab上ではいくつか GUI で設定できるようにしてありますが、それ以外の設定項目もありますので、適宜nvdiffrecの リポジトリ をご確認ください。 !python train.py --config $config_path 上記のコードを実行すると、nvdiffrecの学習が開始されます。学習が完了すると、nvdiffrec/out下に.obj形式、.mtl形式のメッシュとテクス チャフ ァイルが生成されます。 今回使用したデータでは、下記のような結果が得られました。 光の反射が特殊だった上部については推定がうまくいきませんでしたが、それらしきメッシュは作成することができました ! 形状と色が改善できており、そのままNeRFでメッシュを出力するよりも良い結果が得られているといえそうです。メッシュの出力は、マシンスペックやデータ量の増加、チューニングの工夫によってさらに改善することが見込めます。 最終的に、作成したメッシュは、 もちろん Blender などで取り込むことができます ! せっかくの アドベントカレンダー なので、クリスマス仕様にしてみました! おわりに この記事ではnvdiffrecを用いて、 iPhone で撮影した動画から3Dメッシュを作成する手順についてご紹介しました。 3DCG技術に関するAIの発展は目覚ましく、実用的な3DモデルをAIで手軽に生成する未来は着実に近づいていると感じています。ワクワクするような技術が次々と現れる今日ですが、引き続き楽しんでキャッチアップしていきたいと思います。 最後までお読みいただき、ありがとうございました。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました ) NVIDIA Instant NeRF NGP ↩ Extracting Triangular 3D Models, Materials, and Lighting From Images ↩ U 2 -Net: Going Deeper with Nested U-Structure for Salient Object Detection ↩ EISeg: An Efficient Interactive Segmentation Tool based on PaddlePaddle ↩
アバター
テックブログ編集部です。今回は弊社社員が登壇するイベントを紹介します。詳細およびお申込みはリンク先サイトを参照してください。 techplay.jp ご興味あれば、ぜひ登録おねがいします。 基本情報 タイトル: クラウド 時代のエンジニアが知っておくべき、顧客のビジネス課題を解決する クラウド 間のシステム連携/ アーキテクチャ 設計のステップ 日時:2022/12/20(火) 19:00〜20:20 形態:オンライン開催 概要 オンラインでも実店舗と変わらない情報提供を可能にするチャットボット 好みに合った商品を提案するレコメンド機能 迅速かつ正確に対応できるコールセンターシステム などなど、今の時代もっとも重要だと言われている良質な顧客体験の提供を実現するためには SoE (Systems of Engagement)とSoR (Systems of Records)のシステム連携が欠かせません。 今回の勉強会では、複雑化する顧客ニーズへの対応や顧客接点のDX(デジタルトランスフォーメーション)を実現するために、一つのシステムを複数の クラウド サービスを連携させた「マルチ クラウド 」でシステム連携を実現するアプローチを提示します。 複数 クラウド の連携となると、 アーキテクチャ が複雑化してしまう セキュリティの確保が心配になる 運用が複雑になってしまう などのやりづらさやお悩みを抱いている方も多いのではないでしょうか? 実はそのようなお悩みを解決するポイントは、連携する際の" アーキテクチャ 設計の進め方"にあります。 ISIDでは Salesforce を基軸に、 AWS など他の クラウド やオンプレミスにあるシステムと連携・統合させて 顧客対応や マーケティング のためのシステムを構築しています。 システム連携によって実現する機能のビジネス的な価値 クラウド 間のシステム連携を伴う アーキテクチャ 設計の考え方 設計の具体的なステップ、進め方、設計パターン 実際にプロジェクト遂行する時に陥りがちな落とし穴とその乗り越え方 など、 アーキテクチャ の設計ポイントを実例と ケーススタディ を用いながらお話していきます。 執筆: Ishizawa Kento (@kent) 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
テックブログ編集部です。今回は弊社社員が登壇するイベントを紹介します。詳細およびお申込みはリンク先サイトを参照してください。 techplay.jp ご興味あれば、ぜひ登録おねがいします。 基本情報 タイトル: クラウド 時代のエンジニアが知っておくべき、顧客のビジネス課題を解決する クラウド 間のシステム連携/ アーキテクチャ 設計のステップ 日時:2022/12/20(火) 19:00〜20:20 形態:オンライン開催 概要 オンラインでも実店舗と変わらない情報提供を可能にするチャットボット 好みに合った商品を提案するレコメンド機能 迅速かつ正確に対応できるコールセンターシステム などなど、今の時代もっとも重要だと言われている良質な顧客体験の提供を実現するためには SoE (Systems of Engagement)とSoR (Systems of Records)のシステム連携が欠かせません。 今回の勉強会では、複雑化する顧客ニーズへの対応や顧客接点のDX(デジタルトランスフォーメーション)を実現するために、一つのシステムを複数の クラウド サービスを連携させた「マルチ クラウド 」でシステム連携を実現するアプローチを提示します。 複数 クラウド の連携となると、 アーキテクチャ が複雑化してしまう セキュリティの確保が心配になる 運用が複雑になってしまう などのやりづらさやお悩みを抱いている方も多いのではないでしょうか? 実はそのようなお悩みを解決するポイントは、連携する際の" アーキテクチャ 設計の進め方"にあります。 ISIDでは Salesforce を基軸に、 AWS など他の クラウド やオンプレミスにあるシステムと連携・統合させて 顧客対応や マーケティング のためのシステムを構築しています。 システム連携によって実現する機能のビジネス的な価値 クラウド 間のシステム連携を伴う アーキテクチャ 設計の考え方 設計の具体的なステップ、進め方、設計パターン 実際にプロジェクト遂行する時に陥りがちな落とし穴とその乗り越え方 など、 アーキテクチャ の設計ポイントを実例と ケーススタディ を用いながらお話していきます。 執筆: Ishizawa Kento (@kent) 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
みなさんこんにちは、X イノベーション 本部ソフトウェアデザインセンターの徳山です。 本記事は 電通国際情報サービス Advent Calendar 2022 12月9日の記事です。 ISID に入社して1 ヶ月ばかりですが、今まで携わってこなかった技術領域に触れる機会が増えそうなため刺激的な日々を送っております。 さて、これまでユーザーに近い領域の開発、いわゆるフロントエンドを中心とした開発に携わり4年目となります。 保守性や再利用性が高いコードをどのようにしたら書くことができるのかを模索する日々ですが、意外とフロントエンドに関しては手頃にまとまっている文献が少ないと感じます。 そこで今回は、ウェブフロントにおけるコード改善に役立ちそうな書籍を見つけたのでそちらをご紹介したいと思います。 Patterns.dev とは 全体を通した大きな特徴 個別のパターンの紹介 デザインパターン レンダリングパターン パフォーマンスパターン loading に関して bundles に関して まとめ 参考文献 Patterns.dev とは https://www.patterns.dev/ Patterns.dev は、Vanilla JavaScript と React で Web アプリケーションを構築するための デザインパターン と コンポーネント パターンを紹介する書籍です。海外の開発者の方々によって制作され、 ePub や PDF を含めた多くのフォーマットにて無料で公開されています。 Google Chrome チームで働くエンジニアの方が携わっていることもあり、 Chrome チームの立場としての見解が紹介されていたり、 Chrome ブラウザを例とした説明が用いられています。 内容は下記の 3 部から構成されており、それぞれ内容がほとんど独立しているため自分の興味のあるトピックから読み始めることができます。 デザインパターン レンダリング パターン パフォーマンスパターン 全体を通した大きな特徴 書籍にありがちな文章とコードのみが記載されているだけでなく、下記 2 点の特徴があります。 CodeSandbox で動作が確認できる アニメーションで視覚的に学ぶことができる 特に 2 点目は本書籍で最も私が良いと感じている点です。 例えば GoF では Provider パターンというものがあります。 Reactの提供している API として Context.Provider で馴染みがある方も多いかと思います。 これは「複数の コンポーネント で共通のデータを利用可能とする」設計手法ですが、設計パターン自体にあまり触れてこなかった方にはいまいち字面だけだとぴんときづらいかもしれません。私もReactに入門した頃は理解し辛かった記憶があります。 その点、Patterns.dev だと下記のようにアニメーションで役割を把握できます。 このように本書は画像とアニメーションを利用した説明が多く、CodeSandboxによる実際の挙動確認も行えることから言語が英語ながらも比較的参考にしやすい書籍となっています。 個別のパターンの紹介 デザインパターン コーディングにおいて起こりがちな アンチパターン に対処するための設計手法をまとめたものです。 有名なものだと先ほどちらっとご紹介した GoF などがあり、多くの方が一度は耳にしたことがあるかと思います。 Patterns.devで紹介されているパターン一覧 Patterns.dev では デザインパターン に関して下記のように述べられています。 Design patterns are a fundamental part of software development, as they provide typical solutions to commonly recurring problems in software design . Rather than providing specific pieces of software, design patterns are merely concepts that can be used to handle recurring themes in an optimized way. これさえ覚えておけばなんでも解決できる 銀の弾丸 の類ではないことに注意が必要ですが、開発に適切に適用していくことでコードの保守性・再利用性を高めることができます。 最近では フレームワーク や機能(Hooksなど)が良い感じに吸収してくれていることもあり直接紹介されている デザインパターン を適用する機会はそこまで多くないかもしれません。 実際に各パターンではクラス コンポーネント でのコードサンプルをまずは示し、その後関数 コンポーネント やhooksでの実装例を紹介し、場合によっては既にあまり利用されていないことが記述されています。 ただ、その仕組みを知っておけば フレームワーク 内部の仕組みや他言語でのパターン理解が容易になる、他の開発者とのコードに関する共通認識を持つことができるなど間接的なメリットとしては大きいと感じます。 レンダリング パターン 「コンテンツをどこでどのように レンダリング するか」ということに焦点を当てた一連のパターンをまとめたものです。 本書ではこのパターンの必要性が下記のように述べられています。 Choosing the correct pattern could lead to faster builds and excellent loading performance at low processing costs. On the other hand, a wrong choice of pattern can kill an app that could have brought to life a great business idea. So you must ensure that every revolutionary idea you have goes into development with the appropriate rendering pattern. つまり、正しい レンダリング パターンを選択することは実現したいものを適切に形にする上で重要だということが述べられています。正しいパターン選択は Core Web Vitals を改善し、 SEO や優れた UX にも繋がっていきます。 上記の画像にも記載の通り、現在多くの レンダリング パターンがあります。 CSR (Client Side Rendering)や SSR (Server Side Rendering)は認識されている方も多いと思いますが、他のパターンも含めて正確な理解となるとなかなかハードルが高いと感じないでしょうか。 私自身も改めて本書のアニメーションで レンダリング の動きを確認し、サンプルコードを書くことでより理解を深めることができました。 パフォーマンスパターン パフォーマンスを一言で言うことは非常に難しいですが、ここでは「ユーザーのアクションに対して、ユーザーが期待するレスポンスを素早く返すこと」だと解釈しております。 パフォーマンスパターンでは、大別して 2 つの項目がタグ付けされて各パターンが紹介されております。 1 つ目は「loading」、2 つ目は「bundles」です。 loading に関して lazy loading やルーティング分割などがこの項目に該当します。 必要なリソースを必要なときに必要な分だけ取得するという点から各パターンが紹介されています。 見えている範囲のソースをimportする bundles に関して 静的・動的 import や Tree Shaking などがこの項目に該当します。 loading の「必要なものを必要な分だけ」に該当するため、どのパターンも個別ではなく loading とセットでタグ付けされて紹介されています。 動的import JavaScript や React に関するパフォーマンス改善 Tips は多くの記事や書籍で紹介されているものの、それがまとめられていたり、理解しやすいものとなるとぐっと少なくなります。 例えば React の公式ドキュメントではパフォーマンス最適化に関する ドキュメント はあるものの、class コンポーネント を前提とした解説で hooks を利用した開発が多い今の時流には参考にし辛かったりします。 とはいえ、中大規模のアプリケーションでは必要となる知識のため、本書のようにしっかりとページを割いてまとめられていることは多くの開発者にとって大変貢献性が高いのではないかと感じます。 まとめ ここまで Patterns.dev でのパターンを紹介してきました。 英語でとっつきにくい印象を抱かれる方もいるかも知れません。 その場合はDeepLを利用したり、あるいは デザインパターンの章を日本語訳にしてくださっている記事 を参照されるのも良いかと思います。 繰り返しとなりますが、ここで紹介されているパターンはどんな場合にでも確実に使える 銀の弾丸 ではありません。 best ではなく better を探る道具と考え、ぜひ普段の開発に役立てていただければと思います。 参考文献 この記事は下記の情報を参考にして執筆しております。 - Patterns.dev 私たちは同じチームで働いてくれる仲間を探しています。 フロントエンドやバックエンドと特定の領域にとらわれず幅広い技術領域に挑戦してみたい方がいらっしゃいましたら、ぜひご応募ください! ソリューションアーキテクト 執筆: @tokuyama 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
みなさんこんにちは、X イノベーション 本部ソフトウェアデザインセンターの徳山です。 本記事は 電通国際情報サービス Advent Calendar 2022 12月9日の記事です。 ISID に入社して1 ヶ月ばかりですが、今まで携わってこなかった技術領域に触れる機会が増えそうなため刺激的な日々を送っております。 さて、これまでユーザーに近い領域の開発、いわゆるフロントエンドを中心とした開発に携わり4年目となります。 保守性や再利用性が高いコードをどのようにしたら書くことができるのかを模索する日々ですが、意外とフロントエンドに関しては手頃にまとまっている文献が少ないと感じます。 そこで今回は、ウェブフロントにおけるコード改善に役立ちそうな書籍を見つけたのでそちらをご紹介したいと思います。 Patterns.dev とは 全体を通した大きな特徴 個別のパターンの紹介 デザインパターン レンダリングパターン パフォーマンスパターン loading に関して bundles に関して まとめ 参考文献 Patterns.dev とは https://www.patterns.dev/ Patterns.dev は、Vanilla JavaScript と React で Web アプリケーションを構築するための デザインパターン と コンポーネント パターンを紹介する書籍です。海外の開発者の方々によって制作され、 ePub や PDF を含めた多くのフォーマットにて無料で公開されています。 Google Chrome チームで働くエンジニアの方が携わっていることもあり、 Chrome チームの立場としての見解が紹介されていたり、 Chrome ブラウザを例とした説明が用いられています。 内容は下記の 3 部から構成されており、それぞれ内容がほとんど独立しているため自分の興味のあるトピックから読み始めることができます。 デザインパターン レンダリング パターン パフォーマンスパターン 全体を通した大きな特徴 書籍にありがちな文章とコードのみが記載されているだけでなく、下記 2 点の特徴があります。 CodeSandbox で動作が確認できる アニメーションで視覚的に学ぶことができる 特に 2 点目は本書籍で最も私が良いと感じている点です。 例えば GoF では Provider パターンというものがあります。 Reactの提供している API として Context.Provider で馴染みがある方も多いかと思います。 これは「複数の コンポーネント で共通のデータを利用可能とする」設計手法ですが、設計パターン自体にあまり触れてこなかった方にはいまいち字面だけだとぴんときづらいかもしれません。私もReactに入門した頃は理解し辛かった記憶があります。 その点、Patterns.dev だと下記のようにアニメーションで役割を把握できます。 このように本書は画像とアニメーションを利用した説明が多く、CodeSandboxによる実際の挙動確認も行えることから言語が英語ながらも比較的参考にしやすい書籍となっています。 個別のパターンの紹介 デザインパターン コーディングにおいて起こりがちな アンチパターン に対処するための設計手法をまとめたものです。 有名なものだと先ほどちらっとご紹介した GoF などがあり、多くの方が一度は耳にしたことがあるかと思います。 Patterns.devで紹介されているパターン一覧 Patterns.dev では デザインパターン に関して下記のように述べられています。 Design patterns are a fundamental part of software development, as they provide typical solutions to commonly recurring problems in software design . Rather than providing specific pieces of software, design patterns are merely concepts that can be used to handle recurring themes in an optimized way. これさえ覚えておけばなんでも解決できる 銀の弾丸 の類ではないことに注意が必要ですが、開発に適切に適用していくことでコードの保守性・再利用性を高めることができます。 最近では フレームワーク や機能(Hooksなど)が良い感じに吸収してくれていることもあり直接紹介されている デザインパターン を適用する機会はそこまで多くないかもしれません。 実際に各パターンではクラス コンポーネント でのコードサンプルをまずは示し、その後関数 コンポーネント やhooksでの実装例を紹介し、場合によっては既にあまり利用されていないことが記述されています。 ただ、その仕組みを知っておけば フレームワーク 内部の仕組みや他言語でのパターン理解が容易になる、他の開発者とのコードに関する共通認識を持つことができるなど間接的なメリットとしては大きいと感じます。 レンダリング パターン 「コンテンツをどこでどのように レンダリング するか」ということに焦点を当てた一連のパターンをまとめたものです。 本書ではこのパターンの必要性が下記のように述べられています。 Choosing the correct pattern could lead to faster builds and excellent loading performance at low processing costs. On the other hand, a wrong choice of pattern can kill an app that could have brought to life a great business idea. So you must ensure that every revolutionary idea you have goes into development with the appropriate rendering pattern. つまり、正しい レンダリング パターンを選択することは実現したいものを適切に形にする上で重要だということが述べられています。正しいパターン選択は Core Web Vitals を改善し、 SEO や優れた UX にも繋がっていきます。 上記の画像にも記載の通り、現在多くの レンダリング パターンがあります。 CSR (Client Side Rendering)や SSR (Server Side Rendering)は認識されている方も多いと思いますが、他のパターンも含めて正確な理解となるとなかなかハードルが高いと感じないでしょうか。 私自身も改めて本書のアニメーションで レンダリング の動きを確認し、サンプルコードを書くことでより理解を深めることができました。 パフォーマンスパターン パフォーマンスを一言で言うことは非常に難しいですが、ここでは「ユーザーのアクションに対して、ユーザーが期待するレスポンスを素早く返すこと」だと解釈しております。 パフォーマンスパターンでは、大別して 2 つの項目がタグ付けされて各パターンが紹介されております。 1 つ目は「loading」、2 つ目は「bundles」です。 loading に関して lazy loading やルーティング分割などがこの項目に該当します。 必要なリソースを必要なときに必要な分だけ取得するという点から各パターンが紹介されています。 見えている範囲のソースをimportする bundles に関して 静的・動的 import や Tree Shaking などがこの項目に該当します。 loading の「必要なものを必要な分だけ」に該当するため、どのパターンも個別ではなく loading とセットでタグ付けされて紹介されています。 動的import JavaScript や React に関するパフォーマンス改善 Tips は多くの記事や書籍で紹介されているものの、それがまとめられていたり、理解しやすいものとなるとぐっと少なくなります。 例えば React の公式ドキュメントではパフォーマンス最適化に関する ドキュメント はあるものの、class コンポーネント を前提とした解説で hooks を利用した開発が多い今の時流には参考にし辛かったりします。 とはいえ、中大規模のアプリケーションでは必要となる知識のため、本書のようにしっかりとページを割いてまとめられていることは多くの開発者にとって大変貢献性が高いのではないかと感じます。 まとめ ここまで Patterns.dev でのパターンを紹介してきました。 英語でとっつきにくい印象を抱かれる方もいるかも知れません。 その場合はDeepLを利用したり、あるいは デザインパターンの章を日本語訳にしてくださっている記事 を参照されるのも良いかと思います。 繰り返しとなりますが、ここで紹介されているパターンはどんな場合にでも確実に使える 銀の弾丸 ではありません。 best ではなく better を探る道具と考え、ぜひ普段の開発に役立てていただければと思います。 参考文献 この記事は下記の情報を参考にして執筆しております。 - Patterns.dev 私たちは同じチームで働いてくれる仲間を探しています。 フロントエンドやバックエンドと特定の領域にとらわれず幅広い技術領域に挑戦してみたい方がいらっしゃいましたら、ぜひご応募ください! ソリューションアーキテクト 執筆: @tokuyama 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、Stable Diffusion 2.1-AUTOMATIC1111です。 Stable Diffusionも2.1がもう出てしまいました。 AUTOMATIC1111のColab用ノートブック にはまだ Stable Diffusion 2.1 に対応したノートブックが公開されていないので、僕の方で、作っておきました。本家で公開されるまで臨時でお使いください。 AUTOMATIC1111のStable Diffusion 2.1対応ノートブック 追記 本家からもv2.1対応版 がリリースされました。今後は、 こちら をお使いください。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 長い呪文は切り捨てられる編 Stable Diffusion 2.1への対応の仕方 仲間募集 Stable Diffusionの全コンテンツ Stable Diffusion 2.1への対応の仕方 AUTOMATIC 1111のStable Diffusion 2.0対応のノートブック を Google Drive にコピーします。 wget の2行を Stable Diffusion 2.1 用に書き換えます。 !wget https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.ckpt -O /content/stable-diffusion-webui/models/Stable-diffusion/v2-1_768-ema-pruned.ckpt !wget https://raw.githubusercontent.com/Stability-AI/stablediffusion/main/configs/stable-diffusion/v2-inference-v.yaml -O /content/stable-diffusion-webui/models/Stable-diffusion/v2-1_768-ema-pruned.yaml これだけでOKです。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
電通国際情報サービス 、オープン イノベーション ラボの 比嘉康雄 です。 Stable Diffusionシリーズ、今回は、Stable Diffusion 2.1-AUTOMATIC1111です。 Stable Diffusionも2.1がもう出てしまいました。 AUTOMATIC1111のColab用ノートブック にはまだ Stable Diffusion 2.1 に対応したノートブックが公開されていないので、僕の方で、作っておきました。本家で公開されるまで臨時でお使いください。 AUTOMATIC1111のStable Diffusion 2.1対応ノートブック 追記 本家からもv2.1対応版 がリリースされました。今後は、 こちら をお使いください。 Stable Diffusionのおすすめコンテンツはこちら。 Waifu Diffusion 1.3.5_80000 v2.1 金髪美女写真 v2.1 美少女アニメ画 v2.1 AUTOMATIC1111 v2.0 美少女イラスト v1.5 美少女画検証 美少女アニメ画改善版 美少女を高確率で出す呪文編 美少女アニメ画編 美少女写真編 女性イラスト編 長い呪文は切り捨てられる編 Stable Diffusion 2.1への対応の仕方 仲間募集 Stable Diffusionの全コンテンツ Stable Diffusion 2.1への対応の仕方 AUTOMATIC 1111のStable Diffusion 2.0対応のノートブック を Google Drive にコピーします。 wget の2行を Stable Diffusion 2.1 用に書き換えます。 !wget https://huggingface.co/stabilityai/stable-diffusion-2-1/resolve/main/v2-1_768-ema-pruned.ckpt -O /content/stable-diffusion-webui/models/Stable-diffusion/v2-1_768-ema-pruned.ckpt !wget https://raw.githubusercontent.com/Stability-AI/stablediffusion/main/configs/stable-diffusion/v2-inference-v.yaml -O /content/stable-diffusion-webui/models/Stable-diffusion/v2-1_768-ema-pruned.yaml これだけでOKです。 仲間募集 私たちは同じグループで共に働いていただける仲間を募集しています。 現在、以下のような職種を募集しています。 ソリューションアーキテクト AIエンジニア Stable Diffusionの全コンテンツ 人物写真編 レンズ編 画像タイプ編 美少女アニメ画編 美少女写真編 女性イラスト編 美しい夜空を見渡す男編 魅惑的な女アニメ画(トゥーンレンダリング)編 美少女を高確率で出す呪文編 長い呪文は切り捨てられる編 蒸気機関が高度に発達したレトロなアニメ(スチームパンク)の世界観編 A as Bの呪文による画像合成編 かわいい動物の擬人化編 バベルの塔のイラスト編 TPU版の使い方 美少女アニメ画改善版 v1.5 美少女画検証 東京タワーの写真 折り紙合体変形ロボ v2.0 美少女イラスト v2.1 AUTOMATIC1111 v2.1 美少女アニメ画 v2.1 金髪美女写真 Waifu Diffusion 1.3.5_80000 執筆: @higa ( Shodo で執筆されました )
アバター
本記事は 電通国際情報サービス Advent Calendar 2022 の8日目の記事です。 執筆者は X イノベーション 本部 AI トランスフォーメーションセンター所属の山田です。 この記事では先日(2022年11月中旬)に安定版がリリースされた Nuxt 3 について紹介します。 なお、執筆時点での私たちのチームでは、本番プロジェクトへの Nuxt 3 の導入には至っていません。 本記事は、あくまで技術調査をしながら簡単なアプリケーションを開発してみた内容をまとめたものになります。 本記事で紹介する ソースコード は以下の リポジトリ で公開しています。 github.com Nuxt 3 について 開発環境 Nuxt 3 のプロジェクト作成と TypeScript の設定 TypeScript の設定 ESLint の設定 簡単なアプリケーションを開発してみる コンポーネントの設計 pages/index.vueの作成 app.vue の削除 API 呼び出しでのデータ取得 動作確認 コンポーネントの作成 CatCard コンポーネントの作成 CatCardList コンポーネントの作成 pages/index.vueから作成したコンポーネントを呼びだす テスト 準備 コンポーネントレベルのテスト Vitest の VSCode プラグインとデバッグ まとめ Nuxt 3 について はじめに、簡単に Nuxt 3 について紹介しておきます。 Nuxt は Vue.js の フレームワーク です。 冒頭でも述べましたが、2022年11月中旬に Nuxt 3 の安定版がついにリリースされました。 Announcing Nuxt 3.0 stable、 https://nuxt.com/v3 Nuxt 3 のリリースで大きいのは Vue 3 の正式なサポートです。 Vue 3 は 2020年9月にリリースされていましたが、Nuxt 2 ではサポートされていませんでした。 Vue 3 から追加された Compositon API などを利用するために、Nuxt 2 のプロジェクトで Nuxt Composition API などのパッケージを利用している人も多かったのではないでしょうか。 今回リリースされた Nuxt 3 は Vue 3 も公式にサポートしていますし、サーバエンジンも Nitro に刷新され、パフォーマンスも向上しています。 開発環境 本記事での利用した開発環境の情報を記載します。 開発環境/ IDE : GitHub Codespaces リージョン:Southeast Asia スペック:CPU 4コア、メモリ 8 GB Node.js のバージョン管理ツール:nvm Node.js バージョン:v18.12.1 パッケージマネージャー・バージョン:Yarn / 1.22.19 ブラウザ: Google Chrome せっかくなので、 GitHub Codespaces を用いてみました。 Node.js のバージョン管理ソフトには GitHub Codespaces 上でデフォルトでインストールされていた nvm を利用しています。 Node.js のバージョンは LTS の最新バージョンである v18 系を、パッケージマネージャーには Yarn を使っています。 VSCode の 拡張機能 は以下のものを利用します。 Volar Vue Language Features TypeScript Vue Plugin ESLint Chrome の 拡張機能 は以下のものを利用します。 Vue.js devtools Nuxt 3 のプロジェクト作成と TypeScript の設定 Nuxt 3のプロジェクト作成は npx nuxi init コマンドで行います。 npx nuxi init ${ プロジェクト名 } プロジェクト作成段階でできる ディレクト リ構成は以下のようになります。 プロジェクト名 ├── README.md ├── app.vue ├── nuxt.config.ts ├── package.json └── tsconfig.json TypeScript の設定 Nuxt はデフォルトだと TypeScript の厳格な型チェックが有効になっていないので有効にしましょう。 まずは TypeScript と vue- tsc を devDependency に追加します。 yarn add -D typescript vue-tsc 次に nuxt.config.ts を以下のように編集します。 // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig ( { typescript: { shim: false , strict: true , typeCheck: true } , } ); shim: false としているのは、 VSCode で TypeScript Vue Plugin (Volar) を利用するためです。 strict: true にすることで、型チェックが厳格になります。 typeCheck: true としているのは、開発時から型チェックを有効にするためです。Nuxt ではビルドパフォーマンスを最適化するためにデフォルトでは型チェックが行われません。 このあたりの詳細については以下の公式ドキュメントを参照してください。 Nuxt - Installation、 https://nuxt.com/docs/getting-started/installation Nuxt - type-checking、 https://nuxt.com/docs/guide/concepts/typescript また Nuxt 3 からは CLI での型チェックが実行できます。 yarn nuxi typecheck もしも開発中のホットリロード時にビルドパフォーマンスを求めるならば、 typeCheck: false として CLI での手動でのチェックという選択肢もあります。 以下のように npm スクリプト に typecheck コマンドを登録しておいてもいいかもしれません。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck " } } ESLint の設定 次に ESLint の設定をしましょう。 Nuxt では VSCode で開発する際には ESLint プラグイン を利用することが推奨されています。 注意点として Prettier は無効にすることが勧められています。 Nuxt - use-eslint、 https://nuxt.com/docs/community/contribution#use-eslint ということで、まずは ESLint を devDependency に追加します。 yarn add -D @nuxtjs/eslint-config eslint そして ESLint の設定ファイル .eslintrc を作成します。 touch .eslintrc .eslintrc は以下のように記述します。 { " extends ": [ " @nuxtjs/eslint-config-typescript " ] } すでに Prettier を導入している開発者に配慮して、Prettier によるフォーマットがかからないようにしましょう。 .prettierignore を用意し、プロジェクト内のすべてのファイルをフォーマット対象外にしてしまいましょう。 以下が .prettierignore の記述内容になります。 # プロジェクト内のすべてのファイルをPrettierの対象外にする ** .vscode/settings.json を設定し、保存時に ESLint によるフォーマットがかかるようにしましょう。 { " editor.codeActionsOnSave ": { " source.fixAll ": false , " source.fixAll.eslint ": true } } 最後に npm スクリプト に lint コマンドを登録しておきましょう。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck ", " lint ": " eslint --ext .ts,.js,.vue . " , }, } これにより以下のコマンドで ESLint によるコードの静的解析、フォーマットを実施できます。 # 静的解析 yarn lint # フォーマット yarn lint --fix 簡単なアプリケーションを開発してみる 環境が整ったので、ここからは簡単なアプリケーションを開発しながら Nuxt 3 について触れていきましょう。 今回は The Cat API を利用した、猫を愛でることができるアプリケーションを作ります。 The Cat API - Cats as a Service. https://thecatapi.com/ The Cat API では API キーがなくても、10枚まではランダムに猫の画像が取得できます。 完成形のイメージとしては、取得した猫画像をグリッド形式で表示するアプリケーションとします。 コンポーネント の設計 はじめに コンポーネント を設計しましょう。 Vue.js は コンポーネント 指向な フレームワーク ですので、画面デザインから コンポーネント を設計しておくのが大事です。 画像出典: コンポーネント の基本 - コンポーネント の構成、 https://v3.ja.vuejs.org/guide/component-basics.html 今回は手始めに以下のような コンポーネント 構成を考えましょう。 index.vue … ページ コンポーネント 。 API 呼び出しはここで行う。 CatCardList.vue … 猫画像のリストを表示する コンポーネント CatCard.vue … 正方形の猫画像1枚を表示する コンポーネント ツリー形式で可視化すると以下のようになります。 pages/index.vue の作成 はじめに pages コンポーネント の index.vue の追加しましょう。 Nuxt 3 では nuxi add コマンドで簡単に pages コンポーネント を追加できます。 npx nuxi add page index 作成時点では以下のような形になっています。 <script lang="ts" setup></script> <template> <div> Page: foo </div> </template> <style scoped></style> Nuxt 2 までの単一ファイル コンポーネント 内では、 template script style という順番で記述されるのが一般的でしたが、Nuxt 3では script template style の順で記述するのが一般的なようです。 また script 部分は <script setup> 構文での記述がベースとなっています。 <script setup> 構文の詳細については Vue.js 3 の公式ドキュメントを参照してください。 Vue.js - SFC <script setup> 、 https://v3.ja.vuejs.org/api/sfc-script-setup.html app.vue の削除 Nuxt では pages 配下の Vue ファイルでアプリケーションのルーティングが生成されます。 そのため、プロジェクト作成時点でのエントリポイントである app.vue は pages コンポーネント を作成後は不要になるため削除します。 rm app.vue API 呼び出しでのデータ取得 pages/index.vue で The Cat API を呼び出して、データを取得する処理を記述します。 外部 API 呼び出しには Nuxt 組込みの useFetch を利用します。 useFetch、 https://nuxt.com/docs/api/composables/use-fetch 呼び出し前に取得するデータの型を定義しておきましょう。 今回、利用する The Cat API のレスポンスは以下のようになっています。 [ { " id ": " 5ni ", " url ": " https://cdn2.thecatapi.com/images/5ni.jpg ", " width ": 500 , " height ": 375 } ] https://api.thecatapi.com/v1/images/search この情報をもとに型情報を定義しましょう。 型定義は types ディレクト リ配下に記述することにします。 # typesディレクトリの作成 mkdir types touch types/index.ts interface でレスポンスの型を定義します。 export interface CatResponse { id: string ; url: string ; width: number ; height: number ; } そして定義した型情報をインポートしつつ、 useFetch での API 呼び出しのコードを記述します。 <script lang="ts" setup> import { CatResponse } from '~/types' const { pending, error, data } = useFetch<CatResponse[]>( 'https://api.thecatapi.com/v1/images/search?limit=10' ) </script> <template> <div> Page: foo </div> </template> <style scoped></style> useFetch を利用する際に、インポート文を書いていないことに違和感がある方もいるのではないでしょうか? Nuxt 3 では、Auto Imports 機能があり、Vue.js標準の ref や computed Nuxt 組込みの useFetch などの関数を明示的にインポートすることなく記述できます。 Nuxt - auto-imports、 https://nuxt.com/docs/guide/concepts/auto-imports 動作確認 ここまででアプリケーションを起動し、 Chrome の Vue.js devtoolsを確認しましょう。 # 開発サーバでアプリケーションを起動 yarn dev Chrome の Vue.js devtoolsを確認すると、きちんとデータ取得できていることがわかります。 コンポーネント の作成 続いて コンポーネント を作成していきましょう。 コンポーネント も nuxi add コマンドで簡単に追加できます。 # CatCardListコンポーネントの作成 npx nuxi add component CatCardList # CatCardコンポーネントの作成 npx nuxi add component CatCard CatCard コンポーネント の作成 まずはより小さい階層の CatCard コンポーネント を作成します。 CatCard コンポーネント では、 props を介して1つの CatResponse オブジェクトを受け取ります。 そして画像のURLを <img> タグの src に渡します。 以下が CatCard コンポーネント のコードになります。 <script lang="ts" setup> import { CatResponse } from '~/types' interface Props { catData: CatResponse; } defineProps<Props>() </script> <template> <div> <img class="card-img" :src="catData.url" alt="cute cat" :data-testid="catData.id" > </div> </template> <style scoped> .card-img { border-radius: 8px; width: 320px; height: 320px; object-fit: cover; } </style> CatCardList コンポーネント の作成 次に CatCardList コンポーネント を作成します。 CatCardList コンポーネント では、 props を介して CatResponse オブジェクトの配列受け取ります。 そして v-for 構文で配列を展開し、 CatCard コンポーネント を複数描画します。 以下が CatCardList コンポーネント のコードになります。 <script lang="ts" setup> import { CatResponse } from '~/types' interface Props { catList: CatResponse[]; } defineProps<Props>() </script> <template> <div class="card-list" data-testid="cat-list"> <cat-card v-for="(cat, i) in catList" :key="i" :cat-data="cat" /> </div> </template> <style scoped> .card-list { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; } </style> pages/index.vue から作成した コンポーネント を呼びだす 作成した CatCardList コンポーネント を index.vue から呼び出します。 コンポーネント についても Nuxt 側での Auto Imports が有効になっているため、明示的にインポートする必要はありません。 <script lang="ts" setup> import { CatResponse } from '~/types' const { pending, error, data } = useFetch<CatResponse[]>( 'https://api.thecatapi.com/v1/images/search?limit=10' ) </script> <template> <div v-if="!pending && data" class="content"> <cat-card-list :cat-list="data" /> </div> </template> <style scoped> .content { margin: auto; } </style> CatCardList は data の値をプロパティにわたす必要があるため v-if で条件付き レンダリング にします。 あとは、少しレイアウトを整えれば以下のようなアプリケーションが完成します。 isid.github.io テスト 最後にテストについても触れましょう。 Vue.js 3 系からはテストツールとして Vitest が推奨されています。 Vue.js - テスト #推奨事項、 https://ja.vuejs.org/guide/scaling-up/testing.html#recommendation Nuxt 3 の公式ドキュメントではテスト用ツールに @nuxt/test-utils-edge が紹介されていますが、こちらは開発中で不安定です。 なので今回は コンポーネント レベルのテストだけを実施する Vue Testing Library(@testing-library/vue) を用いる方法を紹介します。 なお Vue.js のテストツールとしては、 Vue Test Utils もありますが、 コンポーネント レベルのテストでは @testing-library/vue の利用が推奨されています。 Vue.js - テスト コンポーネント のテスト#推奨事項、 https://ja.vuejs.org/guide/scaling-up/testing.html#recommendation-1 準備 まずは必要なパッケージをインストールします。 テスト時に コンポーネント を描画するDOM環境には happy-dom を使用します。 yarn add -D vitest @testing-library/vue happy-dom Vitest の設定ファイル vitest.config.ts を作成します。 /// <reference types="vitest" /> import { defineConfig } from 'vitest/config' import Vue from '@vitejs/plugin-vue' export default defineConfig ( { plugins: [ Vue () ] , resolve: { alias: { '~' : ` ${__dirname} ` } } , test: { root: '.' , globals: true , environment: 'happy-dom' } } ) npm スクリプト に test コマンドを追加します。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck ", " lint ": " eslint --ext .ts,.js,.vue . ", " test ": " vitest " , }, } コンポーネント レベルのテスト CatCard コンポーネント のテストを記述しましょう。 CatResponse 形式のオブジェクトを props に渡した際に、 コンポーネント が描画できるかテストします。 テストコードは tests ディレクト リ配下に *.spec.ts の形で配置します。 @testing-library/vue でのテストコードは以下のようなります。 コンポーネント が描画できているかの判断には data-testid 属性を使っています。 import { describe , expect , test } from 'vitest' import { render } from '@testing-library/vue' import CatCard from '~/components/CatCard.vue' import { CatResponse } from '~/types' describe ( 'CatCard' , () => { test ( 'コンポーネントの描画ができること' , () => { const catData: CatResponse = { id: 'test' , url: 'https://example.com' , width: 100 , height: 100 } const { getAllByTestId , html } = render ( CatCard , { props: { catData } } ) const results = getAllByTestId ( catData.id ) expect ( results.length ) .toBe ( 1 ) expect ( html ()) .contain ( `data-testid=" ${ catData.id } "` ) } ) } ) テストを実行してみましょう。 yarn test きちんとテストが通れば、以下の出力が得られます。 RERUN tests/components/CatCard.spec.ts x20 ✓ tests/components/CatCard.spec.ts (1) Test Files 1 passed (1) Tests 1 passed (1) Start at 09:40:00 Duration 230ms PASS Waiting for file changes... press h to show help, press q to quit Vitest の VSCode プラグイン と デバッグ テストコードを書くことによって、小さい範囲でコードを動かせるようになりました。 さらに デバッグ もできると開発がより捗ります。 Vitest では公式で VSCode の プラグイン をリリースしており、こちらを活用することでテストコードをもとにデバッガーを起動できます。 Vitest、 https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer VItes - IDE Integrations 、 https://vitest.dev/guide/ide.html テストコードに ブレークポイント を仕込んで、テストタブから「テストの デバッグ 」を選択するとデバッガーが起動できます。 これで開発環境はバッチリですね。 まとめ 本記事では、Nuxt 3 について紹介しました。 今回、記事を書きながら 、これまでの Nuxt の良さを引き継ぎながら正当に進化していると感じました。 nuxi コマンドの充実や TypeScript、 VSCode との親和性の向上、Nitroによるビルド速度の向上など開発がより楽しくなる可能性を感じました。 一方でテストの部分はまだ不安定だと言わざるを得ません。 Nuxt 側の Auto Imports 機能と Vitest の連携がうまくいかなかったり @nuxt/test-utils-edge モジュールが開発中であるため Nuxt 3 のアプリケーションをテストする方法が確立していません。 support for unit testing in a nuxt environment #2465、 https://github.com/nuxt/framework/issues/2465 Nuxt - Testing、 https://nuxt.com/docs/getting-started/testing#testing 直近で Nuxt 3 の導入を検討しているならば、この部分には注意をする必要があります。 最後に、私たちAIトランスフォーメーションセンターでは、一緒に働いてくれる仲間を探しています。 AI 製品開発に興味がある方のご応募をお待ちしております。 AIエンジニア(プロダクト開発) AIプロダクトマネージャー AIコンサルタント AIビジネスプロジェクトマネージャー 執筆: @yamada.y 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
本記事は 電通国際情報サービス Advent Calendar 2022 の8日目の記事です。 執筆者は X イノベーション 本部 AI トランスフォーメーションセンター所属の山田です。 この記事では先日(2022年11月中旬)に安定版がリリースされた Nuxt 3 について紹介します。 なお、執筆時点での私たちのチームでは、本番プロジェクトへの Nuxt 3 の導入には至っていません。 本記事は、あくまで技術調査をしながら簡単なアプリケーションを開発してみた内容をまとめたものになります。 本記事で紹介する ソースコード は以下の リポジトリ で公開しています。 github.com Nuxt 3 について 開発環境 Nuxt 3 のプロジェクト作成と TypeScript の設定 TypeScript の設定 ESLint の設定 簡単なアプリケーションを開発してみる コンポーネントの設計 pages/index.vueの作成 app.vue の削除 API 呼び出しでのデータ取得 動作確認 コンポーネントの作成 CatCard コンポーネントの作成 CatCardList コンポーネントの作成 pages/index.vueから作成したコンポーネントを呼びだす テスト 準備 コンポーネントレベルのテスト Vitest の VSCode プラグインとデバッグ まとめ Nuxt 3 について はじめに、簡単に Nuxt 3 について紹介しておきます。 Nuxt は Vue.js の フレームワーク です。 冒頭でも述べましたが、2022年11月中旬に Nuxt 3 の安定版がついにリリースされました。 Announcing Nuxt 3.0 stable、 https://nuxt.com/v3 Nuxt 3 のリリースで大きいのは Vue 3 の正式なサポートです。 Vue 3 は 2020年9月にリリースされていましたが、Nuxt 2 ではサポートされていませんでした。 Vue 3 から追加された Compositon API などを利用するために、Nuxt 2 のプロジェクトで Nuxt Composition API などのパッケージを利用している人も多かったのではないでしょうか。 今回リリースされた Nuxt 3 は Vue 3 も公式にサポートしていますし、サーバエンジンも Nitro に刷新され、パフォーマンスも向上しています。 開発環境 本記事での利用した開発環境の情報を記載します。 開発環境/ IDE : GitHub Codespaces リージョン:Southeast Asia スペック:CPU 4コア、メモリ 8 GB Node.js のバージョン管理ツール:nvm Node.js バージョン:v18.12.1 パッケージマネージャー・バージョン:Yarn / 1.22.19 ブラウザ: Google Chrome せっかくなので、 GitHub Codespaces を用いてみました。 Node.js のバージョン管理ソフトには GitHub Codespaces 上でデフォルトでインストールされていた nvm を利用しています。 Node.js のバージョンは LTS の最新バージョンである v18 系を、パッケージマネージャーには Yarn を使っています。 VSCode の 拡張機能 は以下のものを利用します。 Volar Vue Language Features TypeScript Vue Plugin ESLint Chrome の 拡張機能 は以下のものを利用します。 Vue.js devtools Nuxt 3 のプロジェクト作成と TypeScript の設定 Nuxt 3のプロジェクト作成は npx nuxi init コマンドで行います。 npx nuxi init ${ プロジェクト名 } プロジェクト作成段階でできる ディレクト リ構成は以下のようになります。 プロジェクト名 ├── README.md ├── app.vue ├── nuxt.config.ts ├── package.json └── tsconfig.json TypeScript の設定 Nuxt はデフォルトだと TypeScript の厳格な型チェックが有効になっていないので有効にしましょう。 まずは TypeScript と vue- tsc を devDependency に追加します。 yarn add -D typescript vue-tsc 次に nuxt.config.ts を以下のように編集します。 // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig ( { typescript: { shim: false , strict: true , typeCheck: true } , } ); shim: false としているのは、 VSCode で TypeScript Vue Plugin (Volar) を利用するためです。 strict: true にすることで、型チェックが厳格になります。 typeCheck: true としているのは、開発時から型チェックを有効にするためです。Nuxt ではビルドパフォーマンスを最適化するためにデフォルトでは型チェックが行われません。 このあたりの詳細については以下の公式ドキュメントを参照してください。 Nuxt - Installation、 https://nuxt.com/docs/getting-started/installation Nuxt - type-checking、 https://nuxt.com/docs/guide/concepts/typescript また Nuxt 3 からは CLI での型チェックが実行できます。 yarn nuxi typecheck もしも開発中のホットリロード時にビルドパフォーマンスを求めるならば、 typeCheck: false として CLI での手動でのチェックという選択肢もあります。 以下のように npm スクリプト に typecheck コマンドを登録しておいてもいいかもしれません。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck " } } ESLint の設定 次に ESLint の設定をしましょう。 Nuxt では VSCode で開発する際には ESLint プラグイン を利用することが推奨されています。 注意点として Prettier は無効にすることが勧められています。 Nuxt - use-eslint、 https://nuxt.com/docs/community/contribution#use-eslint ということで、まずは ESLint を devDependency に追加します。 yarn add -D @nuxtjs/eslint-config eslint そして ESLint の設定ファイル .eslintrc を作成します。 touch .eslintrc .eslintrc は以下のように記述します。 { " extends ": [ " @nuxtjs/eslint-config-typescript " ] } すでに Prettier を導入している開発者に配慮して、Prettier によるフォーマットがかからないようにしましょう。 .prettierignore を用意し、プロジェクト内のすべてのファイルをフォーマット対象外にしてしまいましょう。 以下が .prettierignore の記述内容になります。 # プロジェクト内のすべてのファイルをPrettierの対象外にする ** .vscode/settings.json を設定し、保存時に ESLint によるフォーマットがかかるようにしましょう。 { " editor.codeActionsOnSave ": { " source.fixAll ": false , " source.fixAll.eslint ": true } } 最後に npm スクリプト に lint コマンドを登録しておきましょう。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck ", " lint ": " eslint --ext .ts,.js,.vue . " , }, } これにより以下のコマンドで ESLint によるコードの静的解析、フォーマットを実施できます。 # 静的解析 yarn lint # フォーマット yarn lint --fix 簡単なアプリケーションを開発してみる 環境が整ったので、ここからは簡単なアプリケーションを開発しながら Nuxt 3 について触れていきましょう。 今回は The Cat API を利用した、猫を愛でることができるアプリケーションを作ります。 The Cat API - Cats as a Service. https://thecatapi.com/ The Cat API では API キーがなくても、10枚まではランダムに猫の画像が取得できます。 完成形のイメージとしては、取得した猫画像をグリッド形式で表示するアプリケーションとします。 コンポーネント の設計 はじめに コンポーネント を設計しましょう。 Vue.js は コンポーネント 指向な フレームワーク ですので、画面デザインから コンポーネント を設計しておくのが大事です。 画像出典: コンポーネント の基本 - コンポーネント の構成、 https://v3.ja.vuejs.org/guide/component-basics.html 今回は手始めに以下のような コンポーネント 構成を考えましょう。 index.vue … ページ コンポーネント 。 API 呼び出しはここで行う。 CatCardList.vue … 猫画像のリストを表示する コンポーネント CatCard.vue … 正方形の猫画像1枚を表示する コンポーネント ツリー形式で可視化すると以下のようになります。 pages/index.vue の作成 はじめに pages コンポーネント の index.vue の追加しましょう。 Nuxt 3 では nuxi add コマンドで簡単に pages コンポーネント を追加できます。 npx nuxi add page index 作成時点では以下のような形になっています。 <script lang="ts" setup></script> <template> <div> Page: foo </div> </template> <style scoped></style> Nuxt 2 までの単一ファイル コンポーネント 内では、 template script style という順番で記述されるのが一般的でしたが、Nuxt 3では script template style の順で記述するのが一般的なようです。 また script 部分は <script setup> 構文での記述がベースとなっています。 <script setup> 構文の詳細については Vue.js 3 の公式ドキュメントを参照してください。 Vue.js - SFC <script setup> 、 https://v3.ja.vuejs.org/api/sfc-script-setup.html app.vue の削除 Nuxt では pages 配下の Vue ファイルでアプリケーションのルーティングが生成されます。 そのため、プロジェクト作成時点でのエントリポイントである app.vue は pages コンポーネント を作成後は不要になるため削除します。 rm app.vue API 呼び出しでのデータ取得 pages/index.vue で The Cat API を呼び出して、データを取得する処理を記述します。 外部 API 呼び出しには Nuxt 組込みの useFetch を利用します。 useFetch、 https://nuxt.com/docs/api/composables/use-fetch 呼び出し前に取得するデータの型を定義しておきましょう。 今回、利用する The Cat API のレスポンスは以下のようになっています。 [ { " id ": " 5ni ", " url ": " https://cdn2.thecatapi.com/images/5ni.jpg ", " width ": 500 , " height ": 375 } ] https://api.thecatapi.com/v1/images/search この情報をもとに型情報を定義しましょう。 型定義は types ディレクト リ配下に記述することにします。 # typesディレクトリの作成 mkdir types touch types/index.ts interface でレスポンスの型を定義します。 export interface CatResponse { id: string ; url: string ; width: number ; height: number ; } そして定義した型情報をインポートしつつ、 useFetch での API 呼び出しのコードを記述します。 <script lang="ts" setup> import { CatResponse } from '~/types' const { pending, error, data } = useFetch<CatResponse[]>( 'https://api.thecatapi.com/v1/images/search?limit=10' ) </script> <template> <div> Page: foo </div> </template> <style scoped></style> useFetch を利用する際に、インポート文を書いていないことに違和感がある方もいるのではないでしょうか? Nuxt 3 では、Auto Imports 機能があり、Vue.js標準の ref や computed Nuxt 組込みの useFetch などの関数を明示的にインポートすることなく記述できます。 Nuxt - auto-imports、 https://nuxt.com/docs/guide/concepts/auto-imports 動作確認 ここまででアプリケーションを起動し、 Chrome の Vue.js devtoolsを確認しましょう。 # 開発サーバでアプリケーションを起動 yarn dev Chrome の Vue.js devtoolsを確認すると、きちんとデータ取得できていることがわかります。 コンポーネント の作成 続いて コンポーネント を作成していきましょう。 コンポーネント も nuxi add コマンドで簡単に追加できます。 # CatCardListコンポーネントの作成 npx nuxi add component CatCardList # CatCardコンポーネントの作成 npx nuxi add component CatCard CatCard コンポーネント の作成 まずはより小さい階層の CatCard コンポーネント を作成します。 CatCard コンポーネント では、 props を介して1つの CatResponse オブジェクトを受け取ります。 そして画像のURLを <img> タグの src に渡します。 以下が CatCard コンポーネント のコードになります。 <script lang="ts" setup> import { CatResponse } from '~/types' interface Props { catData: CatResponse; } defineProps<Props>() </script> <template> <div> <img class="card-img" :src="catData.url" alt="cute cat" :data-testid="catData.id" > </div> </template> <style scoped> .card-img { border-radius: 8px; width: 320px; height: 320px; object-fit: cover; } </style> CatCardList コンポーネント の作成 次に CatCardList コンポーネント を作成します。 CatCardList コンポーネント では、 props を介して CatResponse オブジェクトの配列受け取ります。 そして v-for 構文で配列を展開し、 CatCard コンポーネント を複数描画します。 以下が CatCardList コンポーネント のコードになります。 <script lang="ts" setup> import { CatResponse } from '~/types' interface Props { catList: CatResponse[]; } defineProps<Props>() </script> <template> <div class="card-list" data-testid="cat-list"> <cat-card v-for="(cat, i) in catList" :key="i" :cat-data="cat" /> </div> </template> <style scoped> .card-list { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; } </style> pages/index.vue から作成した コンポーネント を呼びだす 作成した CatCardList コンポーネント を index.vue から呼び出します。 コンポーネント についても Nuxt 側での Auto Imports が有効になっているため、明示的にインポートする必要はありません。 <script lang="ts" setup> import { CatResponse } from '~/types' const { pending, error, data } = useFetch<CatResponse[]>( 'https://api.thecatapi.com/v1/images/search?limit=10' ) </script> <template> <div v-if="!pending && data" class="content"> <cat-card-list :cat-list="data" /> </div> </template> <style scoped> .content { margin: auto; } </style> CatCardList は data の値をプロパティにわたす必要があるため v-if で条件付き レンダリング にします。 あとは、少しレイアウトを整えれば以下のようなアプリケーションが完成します。 isid.github.io テスト 最後にテストについても触れましょう。 Vue.js 3 系からはテストツールとして Vitest が推奨されています。 Vue.js - テスト #推奨事項、 https://ja.vuejs.org/guide/scaling-up/testing.html#recommendation Nuxt 3 の公式ドキュメントではテスト用ツールに @nuxt/test-utils-edge が紹介されていますが、こちらは開発中で不安定です。 なので今回は コンポーネント レベルのテストだけを実施する Vue Testing Library(@testing-library/vue) を用いる方法を紹介します。 なお Vue.js のテストツールとしては、 Vue Test Utils もありますが、 コンポーネント レベルのテストでは @testing-library/vue の利用が推奨されています。 Vue.js - テスト コンポーネント のテスト#推奨事項、 https://ja.vuejs.org/guide/scaling-up/testing.html#recommendation-1 準備 まずは必要なパッケージをインストールします。 テスト時に コンポーネント を描画するDOM環境には happy-dom を使用します。 yarn add -D vitest @testing-library/vue happy-dom Vitest の設定ファイル vitest.config.ts を作成します。 /// <reference types="vitest" /> import { defineConfig } from 'vitest/config' import Vue from '@vitejs/plugin-vue' export default defineConfig ( { plugins: [ Vue () ] , resolve: { alias: { '~' : ` ${__dirname} ` } } , test: { root: '.' , globals: true , environment: 'happy-dom' } } ) npm スクリプト に test コマンドを追加します。 { " scripts ": { " build ": " nuxt build ", " dev ": " nuxt dev ", " generate ": " nuxt generate ", " preview ": " nuxt preview ", " postinstall ": " nuxt prepare ", " typecheck ": " nuxt typecheck ", " lint ": " eslint --ext .ts,.js,.vue . ", " test ": " vitest " , }, } コンポーネント レベルのテスト CatCard コンポーネント のテストを記述しましょう。 CatResponse 形式のオブジェクトを props に渡した際に、 コンポーネント が描画できるかテストします。 テストコードは tests ディレクト リ配下に *.spec.ts の形で配置します。 @testing-library/vue でのテストコードは以下のようなります。 コンポーネント が描画できているかの判断には data-testid 属性を使っています。 import { describe , expect , test } from 'vitest' import { render } from '@testing-library/vue' import CatCard from '~/components/CatCard.vue' import { CatResponse } from '~/types' describe ( 'CatCard' , () => { test ( 'コンポーネントの描画ができること' , () => { const catData: CatResponse = { id: 'test' , url: 'https://example.com' , width: 100 , height: 100 } const { getAllByTestId , html } = render ( CatCard , { props: { catData } } ) const results = getAllByTestId ( catData.id ) expect ( results.length ) .toBe ( 1 ) expect ( html ()) .contain ( `data-testid=" ${ catData.id } "` ) } ) } ) テストを実行してみましょう。 yarn test きちんとテストが通れば、以下の出力が得られます。 RERUN tests/components/CatCard.spec.ts x20 ✓ tests/components/CatCard.spec.ts (1) Test Files 1 passed (1) Tests 1 passed (1) Start at 09:40:00 Duration 230ms PASS Waiting for file changes... press h to show help, press q to quit Vitest の VSCode プラグイン と デバッグ テストコードを書くことによって、小さい範囲でコードを動かせるようになりました。 さらに デバッグ もできると開発がより捗ります。 Vitest では公式で VSCode の プラグイン をリリースしており、こちらを活用することでテストコードをもとにデバッガーを起動できます。 Vitest、 https://marketplace.visualstudio.com/items?itemName=ZixuanChen.vitest-explorer VItes - IDE Integrations 、 https://vitest.dev/guide/ide.html テストコードに ブレークポイント を仕込んで、テストタブから「テストの デバッグ 」を選択するとデバッガーが起動できます。 これで開発環境はバッチリですね。 まとめ 本記事では、Nuxt 3 について紹介しました。 今回、記事を書きながら 、これまでの Nuxt の良さを引き継ぎながら正当に進化していると感じました。 nuxi コマンドの充実や TypeScript、 VSCode との親和性の向上、Nitroによるビルド速度の向上など開発がより楽しくなる可能性を感じました。 一方でテストの部分はまだ不安定だと言わざるを得ません。 Nuxt 側の Auto Imports 機能と Vitest の連携がうまくいかなかったり @nuxt/test-utils-edge モジュールが開発中であるため Nuxt 3 のアプリケーションをテストする方法が確立していません。 support for unit testing in a nuxt environment #2465、 https://github.com/nuxt/framework/issues/2465 Nuxt - Testing、 https://nuxt.com/docs/getting-started/testing#testing 直近で Nuxt 3 の導入を検討しているならば、この部分には注意をする必要があります。 最後に、私たちAIトランスフォーメーションセンターでは、一緒に働いてくれる仲間を探しています。 AI 製品開発に興味がある方のご応募をお待ちしております。 AIエンジニア(プロダクト開発) AIプロダクトマネージャー AIコンサルタント AIビジネスプロジェクトマネージャー 執筆: @yamada.y 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
みなさんこんにちは! 電通国際情報サービス (ISID)クロス イノベーション 本部 AIトランスフォーメーションセンター(AITC) インドネシア 出身のファイサル ハディプトラと申します。この記事は 電通国際情報サービス Advent Calendar 2022 の12月7日の記事です。 先日、TECHPLAYで「AI搭載検索システム」について登壇いたしました。 Techplayイベントページ 今回は、AI搭載検索システムに関連する「ナレッジグラフを搭載した検索システム」について紹介します。 AI搭載検索システム 検索といえば、皆さんはきっと Google 検索をイメージしています。最近の Google 検索は、昔とは違ってAI技術を活用することで、ただのキーワード検索を超えた特徴を持っています。 Google 検索に慣れているほとんどのユーザーは検索システムを使用するときに、以下のようなことを期待します。 ドメイン 理解(Domain-aware) :ユーザーのクエリ内のキーワードに該当する概念を認識して自動的にその概念のカテゴリや属性などをクエリに付加する。例えば:「ISID」というクエリを打ったときに、「会社」のカテゴリ、「 電通 国際情報」の別名、と「品川」の本社所在地などの情報をクエリに付加する。 文脈とユーザーの理解(Contextual and Personalized) :ユーザーの好み・プロフィールを考慮してクエリと検索結果の関連度を調整する。例えば:エンジニアが「 Python 」というクエリを打ったときに、蛇の Python ではなく、 プログラミング言語 の Python を記載する記事を返す。 対話型(Conversational) : 自然言語 を理解し、前に検索したものを考慮する。例えば:「コロナ」と検索した後、次に「mrna」と検索すると、モデルなのワクチン情報が出てくる。 マルチモーダル(Multi-modal) :テキストに限らず、音声、画像、映像などに対応する。 知能的(Intelligent) :データが溜まっていけばいくほど自己改善する。例えば:誤字自動訂正や自動補完機能がだんだん賢くなる。 支援型(Assistive) :検索以上に自動的に適切なアクションを実行する。例えば:映画名を検索すると、検索結果カードの下の部分で「予約ボタン」が表示される。 これらの特徴は共通のゴールを持っています。ユーザーの意図(ユーザーが探したいもの)を理解することです。ユーザーが探したいものは、ユーザー自身しか分からないので、検索システムの開発側はユーザー意図を3つの次元に分割し、それぞれの次元を 定量 化します。 コンテンツ理解 :検索対象文書とユーザーが入力したキーワードのクエリそのものを理解する。 ユーザー理解 :検索システムのユーザーの好みやプロフィールを理解する。 ドメイン 理解 :検索システムをデプロイする業務/ ドメイン 知識を理解する。 次のベン図に書いていたように各次元の代表技術と2つの次元を組み合わせた技術が記載されています。 コンテンツ理解 → キーワード検索( 全文検索 ) ユーザー理解 → 協調フィルタリング (推薦システム) ドメイン 理解 → ナレッジグラフ コンテンツ理解 + ユーザー理解 → パーソナライズド検索 ユーザー理解 + ドメイン 理解 → マルチモーダル推薦 コンテンツ理解 + ドメイン 理解 → セマンティック検索 今回は、ナレッジグラフを搭載したセマンティック検索システムを紹介します。 ナレッジグラフを搭載したセマンティック検索 検索エンジン ナレッジグラフを導入する前に、まず、 検索エンジン の構成を解説します。 検索エンジン では、文書データを 転置インデックス というデータ構造で管理しています。転置とは、本の索引のように、単語の一覧を並べて、その単語を含む文章にひも付いています。 転置インデックス としてデータを管理することで検索スピードが速くなります。 転置インデックス ができたら、ユーザーがクエリを入力する時に、以下の処理を行います。 クエリの解析 :クエリをキーワード・単語に分割します。 フィルターリング : 転置インデックス からそれらのキーワードを含む文書を取得します。 関連度の計算 : 取得した文書とクエリの関連度を計算します。計算方法は様々ですが、よく使われるのはBM25です。 検索結果提供 :最後に、関連度順で文書を並べてユーザーに返します。 検索エンジン を仕様することで、文書入れるだけでOut-of-the-boxで 全文検索 ができます。最初は、このようなキーワード検索だけで十分に情報検索ができますが、データがだんだん溜まっていけばいくほど、キーワード検索だけで得られない場合が多いです。例えば、Eコマースのシステムを例にして、ユーザーが iPad をクエリとして検索するときに、出てくるのは「 iPad のケース」や「 iPad の充電器」など iPad 本体ではありません。 この場合は、明らかに生のキーワード検索だけで、ユーザーが探したい情報を得ることはできません。1つの解決方法としては、ユーザーのクリック情報を収集して 協調フィルタリング といった方法を使用して、検索結果を調整するのはできます。ただし、このアプローチの欠点としては、ユーザーの行動が制御できず、データの偏りが生じると、変な検索結果が出ています。そのために、今回は、 ナレッジグラフ を導入して、検索対象データとクエリに意味を持たせるべきです。 ナレッジグラフ ナレッジグラフとは、簡単に言うと人間の知識をグラフ形式で表現するものです。世の中での定義は様々ですが、検索の文脈では、人の知識を表現するために5つのレベルで表現できます。 言い換え( Alternative Labels)同じ意味を表現する単語。例えば:チョコレート => チョコ; 国際連合 => 国連。 同義語・類義語(Synonyms)近い意味を表現する単語。例えば:人間 => 人、人類;食べ物 => 食材、食料、フード、食品。 分類体系(Taxonomy)ものを階層的なカテゴリに分類する。例えば:加藤ーIS_A→人間、人間ーIS_A→哺乳類、哺乳類ーIS_A→動物。 オントロジー (Ontology)ものの種類(タイプ・クラス)の関連性を表現する。例えば:動物ー食べる→食べ物、人間 ナレッジグラフ(Knowledge Graph) オントロジー を インスタンス 化したものを同じグラフで表現する。例えば:加藤ーIS_A→人間、加藤ー食べる→食べ物 基本的に、ナレッジグラフは構造データであるので、データを簡単に探索できます。例えば、 Google 検索で「日本」というクエリを打った時に、検索結果の右側に日本のナレッジパネルが出てきます。そのナレッジパネルから日本の首都である「東京」をクリックすると、東京のナレッジパネルをすぐに表示できます。 セマンティック検索 ナレッジグラフと 検索エンジン の双方の利点を活用するとセマンティック検索が実現できます。セマンティック検索では、ユーザーが打ったクエリからエンティティ(Entity)と関係(Relation)を抽出します。そして、「エンティティ」と「関係」の情報を使って、以下の処理を行うことができます。 [1] 得られた情報がたどり着くまでナレッジグラフに対してグラフ走査(Graph Traversal)を行います。 例えば:「ISID近くの中華」、解析結果のイメージは以下のとおりです。 対象クラス: 中華レストラン 絞り込み条件: 距離: 条件:近い(5km以内) 原点:京王品川ビル(ISID本社) この解析結果をもとに、GraphQL、 Cypher QL(Neo4j)、SPARQLなどに変換すれば、グラフ走査を行うことができ、最後に対象ドキュメントまでたどり着きます。 Cypher Scriptのクエリイメージは以下のとおりです。 MATCH (a: Article)-[:HAS_MENTION]->(r:ChineseRestaurant) MATCH (c: Company {english_name: ISID})-[:HAS_HEADQUARTER]->(o:Office) WHERE point.distance(r.geolocation, o.geolocation) <= 5000 RETURN a アプローチ[1]では、高度なセマンティック解析処理と高度なセマンティック情報を持つナレッジグラフが必要で、難易度が高いです。もちろんこのようなシステムを実現できれば理想的であるが、人手で作るのは大変ですし、自動で作るのはかなり難しいです。 [2] 関連するエンティティをナレッジグラフから抽出してクエリを拡張してから 検索エンジン にクエリを入力します。 このアプローチでは、クエリを解析して直接ナレッジグラフから答えを抽出するのではなく、ナレッジグラフから情報を抽出して、クエリを拡張します。 同じ例の「ISID近くの中華」ですと、ISIDという言葉は「 電通国際情報サービス 」や「品川」で、中華という言葉は「レストラン」や「中華料理」などナレッジグラフから抽出します。そのあと、オリジナルクエリにそれらの言葉を追加して、 検索エンジン のクエリを作って投げます。 Elasticsearchのクエリイメージは以下のとおりです。 { " query ": { " query_string ": { " fields ": [ " title ", " body ", " category " ] , " query ": " (ISID^10 OR 電通国際情報サービス OR 品川) AND (中華^10 OR レストラン OR 中華料理) " } } } アプローチ1に比べて、このアプローチの方がより現実的です。高度なセマンティック情報を持つナレッジグラフの必要性が低く、has_related_termsという関係性を表現したナレッジグラフで十分です。もちろん、アプローチ1の方は検索精度が高いですが、最初の段階で、このアプローチはやりやすいと考えられます。 まとめ 今回は、検索システムにナレッジグラフの導入イメージを紹介しました。イメージがつくように簡単なNeo4jの Cypher スクリプト とElasticsearchクエリの例をあげてみました。ナレッジグラフを活用する前に、ナレッジグラフ構築が必要で、このステップは一番大変だと思います。ISIDでは、日本語の文書からナレッジグラフを構築する技術の研究を行っています。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 AIエンジニア(プロダクト開発) AIプロダクトマネージャー AIコンサルタント AIビジネスプロジェクトマネージャー 執筆: @faisalhadiputra 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
みなさんこんにちは! 電通国際情報サービス (ISID)クロス イノベーション 本部 AIトランスフォーメーションセンター(AITC) インドネシア 出身のファイサル ハディプトラと申します。この記事は 電通国際情報サービス Advent Calendar 2022 の12月7日の記事です。 先日、TECHPLAYで「AI搭載検索システム」について登壇いたしました。 Techplayイベントページ 今回は、AI搭載検索システムに関連する「ナレッジグラフを搭載した検索システム」について紹介します。 AI搭載検索システム 検索といえば、皆さんはきっと Google 検索をイメージしています。最近の Google 検索は、昔とは違ってAI技術を活用することで、ただのキーワード検索を超えた特徴を持っています。 Google 検索に慣れているほとんどのユーザーは検索システムを使用するときに、以下のようなことを期待します。 ドメイン 理解(Domain-aware) :ユーザーのクエリ内のキーワードに該当する概念を認識して自動的にその概念のカテゴリや属性などをクエリに付加する。例えば:「ISID」というクエリを打ったときに、「会社」のカテゴリ、「 電通 国際情報」の別名、と「品川」の本社所在地などの情報をクエリに付加する。 文脈とユーザーの理解(Contextual and Personalized) :ユーザーの好み・プロフィールを考慮してクエリと検索結果の関連度を調整する。例えば:エンジニアが「 Python 」というクエリを打ったときに、蛇の Python ではなく、 プログラミング言語 の Python を記載する記事を返す。 対話型(Conversational) : 自然言語 を理解し、前に検索したものを考慮する。例えば:「コロナ」と検索した後、次に「mrna」と検索すると、モデルなのワクチン情報が出てくる。 マルチモーダル(Multi-modal) :テキストに限らず、音声、画像、映像などに対応する。 知能的(Intelligent) :データが溜まっていけばいくほど自己改善する。例えば:誤字自動訂正や自動補完機能がだんだん賢くなる。 支援型(Assistive) :検索以上に自動的に適切なアクションを実行する。例えば:映画名を検索すると、検索結果カードの下の部分で「予約ボタン」が表示される。 これらの特徴は共通のゴールを持っています。ユーザーの意図(ユーザーが探したいもの)を理解することです。ユーザーが探したいものは、ユーザー自身しか分からないので、検索システムの開発側はユーザー意図を3つの次元に分割し、それぞれの次元を 定量 化します。 コンテンツ理解 :検索対象文書とユーザーが入力したキーワードのクエリそのものを理解する。 ユーザー理解 :検索システムのユーザーの好みやプロフィールを理解する。 ドメイン 理解 :検索システムをデプロイする業務/ ドメイン 知識を理解する。 次のベン図に書いていたように各次元の代表技術と2つの次元を組み合わせた技術が記載されています。 コンテンツ理解 → キーワード検索( 全文検索 ) ユーザー理解 → 協調フィルタリング (推薦システム) ドメイン 理解 → ナレッジグラフ コンテンツ理解 + ユーザー理解 → パーソナライズド検索 ユーザー理解 + ドメイン 理解 → マルチモーダル推薦 コンテンツ理解 + ドメイン 理解 → セマンティック検索 今回は、ナレッジグラフを搭載したセマンティック検索システムを紹介します。 ナレッジグラフを搭載したセマンティック検索 検索エンジン ナレッジグラフを導入する前に、まず、 検索エンジン の構成を解説します。 検索エンジン では、文書データを 転置インデックス というデータ構造で管理しています。転置とは、本の索引のように、単語の一覧を並べて、その単語を含む文章にひも付いています。 転置インデックス としてデータを管理することで検索スピードが速くなります。 転置インデックス ができたら、ユーザーがクエリを入力する時に、以下の処理を行います。 クエリの解析 :クエリをキーワード・単語に分割します。 フィルターリング : 転置インデックス からそれらのキーワードを含む文書を取得します。 関連度の計算 : 取得した文書とクエリの関連度を計算します。計算方法は様々ですが、よく使われるのはBM25です。 検索結果提供 :最後に、関連度順で文書を並べてユーザーに返します。 検索エンジン を仕様することで、文書入れるだけでOut-of-the-boxで 全文検索 ができます。最初は、このようなキーワード検索だけで十分に情報検索ができますが、データがだんだん溜まっていけばいくほど、キーワード検索だけで得られない場合が多いです。例えば、Eコマースのシステムを例にして、ユーザーが iPad をクエリとして検索するときに、出てくるのは「 iPad のケース」や「 iPad の充電器」など iPad 本体ではありません。 この場合は、明らかに生のキーワード検索だけで、ユーザーが探したい情報を得ることはできません。1つの解決方法としては、ユーザーのクリック情報を収集して 協調フィルタリング といった方法を使用して、検索結果を調整するのはできます。ただし、このアプローチの欠点としては、ユーザーの行動が制御できず、データの偏りが生じると、変な検索結果が出ています。そのために、今回は、 ナレッジグラフ を導入して、検索対象データとクエリに意味を持たせるべきです。 ナレッジグラフ ナレッジグラフとは、簡単に言うと人間の知識をグラフ形式で表現するものです。世の中での定義は様々ですが、検索の文脈では、人の知識を表現するために5つのレベルで表現できます。 言い換え( Alternative Labels)同じ意味を表現する単語。例えば:チョコレート => チョコ; 国際連合 => 国連。 同義語・類義語(Synonyms)近い意味を表現する単語。例えば:人間 => 人、人類;食べ物 => 食材、食料、フード、食品。 分類体系(Taxonomy)ものを階層的なカテゴリに分類する。例えば:加藤ーIS_A→人間、人間ーIS_A→哺乳類、哺乳類ーIS_A→動物。 オントロジー (Ontology)ものの種類(タイプ・クラス)の関連性を表現する。例えば:動物ー食べる→食べ物、人間 ナレッジグラフ(Knowledge Graph) オントロジー を インスタンス 化したものを同じグラフで表現する。例えば:加藤ーIS_A→人間、加藤ー食べる→食べ物 基本的に、ナレッジグラフは構造データであるので、データを簡単に探索できます。例えば、 Google 検索で「日本」というクエリを打った時に、検索結果の右側に日本のナレッジパネルが出てきます。そのナレッジパネルから日本の首都である「東京」をクリックすると、東京のナレッジパネルをすぐに表示できます。 セマンティック検索 ナレッジグラフと 検索エンジン の双方の利点を活用するとセマンティック検索が実現できます。セマンティック検索では、ユーザーが打ったクエリからエンティティ(Entity)と関係(Relation)を抽出します。そして、「エンティティ」と「関係」の情報を使って、以下の処理を行うことができます。 [1] 得られた情報がたどり着くまでナレッジグラフに対してグラフ走査(Graph Traversal)を行います。 例えば:「ISID近くの中華」、解析結果のイメージは以下のとおりです。 対象クラス: 中華レストラン 絞り込み条件: 距離: 条件:近い(5km以内) 原点:京王品川ビル(ISID本社) この解析結果をもとに、GraphQL、 Cypher QL(Neo4j)、SPARQLなどに変換すれば、グラフ走査を行うことができ、最後に対象ドキュメントまでたどり着きます。 Cypher Scriptのクエリイメージは以下のとおりです。 MATCH (a: Article)-[:HAS_MENTION]->(r:ChineseRestaurant) MATCH (c: Company {english_name: ISID})-[:HAS_HEADQUARTER]->(o:Office) WHERE point.distance(r.geolocation, o.geolocation) <= 5000 RETURN a アプローチ[1]では、高度なセマンティック解析処理と高度なセマンティック情報を持つナレッジグラフが必要で、難易度が高いです。もちろんこのようなシステムを実現できれば理想的であるが、人手で作るのは大変ですし、自動で作るのはかなり難しいです。 [2] 関連するエンティティをナレッジグラフから抽出してクエリを拡張してから 検索エンジン にクエリを入力します。 このアプローチでは、クエリを解析して直接ナレッジグラフから答えを抽出するのではなく、ナレッジグラフから情報を抽出して、クエリを拡張します。 同じ例の「ISID近くの中華」ですと、ISIDという言葉は「 電通国際情報サービス 」や「品川」で、中華という言葉は「レストラン」や「中華料理」などナレッジグラフから抽出します。そのあと、オリジナルクエリにそれらの言葉を追加して、 検索エンジン のクエリを作って投げます。 Elasticsearchのクエリイメージは以下のとおりです。 { " query ": { " query_string ": { " fields ": [ " title ", " body ", " category " ] , " query ": " (ISID^10 OR 電通国際情報サービス OR 品川) AND (中華^10 OR レストラン OR 中華料理) " } } } アプローチ1に比べて、このアプローチの方がより現実的です。高度なセマンティック情報を持つナレッジグラフの必要性が低く、has_related_termsという関係性を表現したナレッジグラフで十分です。もちろん、アプローチ1の方は検索精度が高いですが、最初の段階で、このアプローチはやりやすいと考えられます。 まとめ 今回は、検索システムにナレッジグラフの導入イメージを紹介しました。イメージがつくように簡単なNeo4jの Cypher スクリプト とElasticsearchクエリの例をあげてみました。ナレッジグラフを活用する前に、ナレッジグラフ構築が必要で、このステップは一番大変だと思います。ISIDでは、日本語の文書からナレッジグラフを構築する技術の研究を行っています。 私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募をお待ちしています。 AIエンジニア(プロダクト開発) AIプロダクトマネージャー AIコンサルタント AIビジネスプロジェクトマネージャー 執筆: @faisalhadiputra 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの柴田です。 これは 電通国際情報サービス Advent Calendar 2022 6日目の記事です。5日目の昨日は、もう一人の柴田さんの記事「 Argo CDを使ってIstioをバージョンアップする 」でした。 はじめに Webアプリケーションの構成 動作イメージ コードサンプル はじめに 社内で Excel ファイルを扱う業務があり、特定の Excel ファイルをテンプレートとして都度ファイルをコピーする形で運用しています。 Excel ファイルはメンテナンス時の差分管理が Excel 単体の機能では難しく、複数人での修正も可能ですが、個人的には変更履歴があまり視認性の良いものではないと考えています。 そこで、 Excel ファイルに記載する内容を別途テキストベースで差分管理し、修正したテキストを Excel ファイルに流し込むシステムを構築することになりました。 また、併せてNext.jsを利用しWebアプリケーション化も実現して、 Excel ファイルに追加するテキストもWebアプリケーション上から入力できるような仕組みにしています。 今回作成しているWebアプリケーションは、Next.jsとTypeScriptを利用しています。 その中で、 Amazon S3 に保存した Excel ファイル(拡張子xlsx)を取得して、 Excel ファイルを加工処理してからクライアント( Webブラウザ )に返却する、という処理を紹介します。 Webアプリケーションの構成 前述の通り、 Amazon S3 を利用しているため、Webシステムは AWS 上に構築しています。 実際はもう少し複雑なシステム構成ですが、以下は、今回紹介する Excel 処理部分のフローを抜粋した図です。 Webブラウザ からリク エス トを受けたWebアプリケーション(Next.js)が、バックエンド側で Amazon S3 から Excel ファイルを取得します。取得した Excel ファイルの加工処理をした後、 Webブラウザ 側に返却する流れです。 Amazon S3 からのデータ取得のライブラリは AWS SDK for JavaScript v3 、 Excel ファイルの加工のライブラリは ExcelJS を利用しています。 動作イメージ ダウンロードボタンを押すと、 /api/download にリク エス トが送信され、加工したファイルがダウンロードされます。 コードサンプル Next.jsのプロジェクト作成は、以下の陳さんの記事を参考にしました。 tech.isid.co.jp まずはフロント側です。 // pages/index.tsx import styles from '../styles/Home.module.css' const Home = () => { const download = async ( fileName: string ) => { const response = await fetch ( `/api/download` , { method: 'GET' } ) try { if ( response. status !== 200 ) { throw new Error () } else { const blob = await response.blob () const blobFile = new Blob ( [ blob ] , { type : 'application/xlsx' } ) const a = document .createElement ( 'a' ) a.style.display = 'none' document .body.appendChild ( a ) const url = window .URL.createObjectURL ( blobFile ) a.href = url a.download = fileName a.click () window .URL.revokeObjectURL ( url ) } } catch ( e: unknown ) { console .error ( e ) } } return ( < div className = { styles.container } > < main className = { styles.main } > < button onClick = { () => download ( 'ダウンロードファイル名.xlsx' ) } > ダウンロード < /button > < /main > < /div > ) } export default Home サンプルコードでは、ボタンをクリックするとバックエンドの API にリク エス トし、レスポンスを組み立てて、ファイル保存のダイアログを表示させる形にしています。 次に API です。 // pages/api/download.ts import { Readable } from 'stream' import * as ExcelJS from 'exceljs' import type { NextApiRequest , NextApiResponse } from 'next' import { getObject } from '../../src/aws/s3' export default async function download ( req: NextApiRequest , res: NextApiResponse ) : Promise < void > { try { const s3Output = await getObject ( 'bucket' , 'key' ) if ( s3Output.Body instanceof Readable ) { const s3OutputStream = s3Output.Body as Readable res.setHeader ( 'Content-Type' , 'application/xlsx' ) res. status( 200 ) const workbook = new ExcelJS.Workbook () await workbook.xlsx.read ( s3OutputStream ) const sheet = workbook.getWorksheet ( 'Sheet1' ) sheet.getRow ( 1 ) .getCell ( 1 ) .value = 'テスト' await workbook.xlsx.write ( res ) } return } catch ( e: unknown ) { return res. status( 500 ) .json ( { message: 'Internal Server Error' } ) } } // src/aws/s3.ts import { GetObjectCommand , GetObjectCommandOutput , S3Client } from '@aws-sdk/client-s3' export async function getObject ( bucket: string , key: string ) : Promise < GetObjectCommandOutput > { const params = { Bucket: bucket , Key: key , } const command = new GetObjectCommand ( params ) return await new S3Client ( { region: 'ap-northeast-1' } ) .send ( command ) } Amazon S3 にリク エス トを送信し、レスポンスを受け取ります。 受け取ったStreamを順次処理するため、そのままExcelJSに渡しています。 ExcelJSでは、Streamをそのまま処理してくれます。 参考 github.com ExcelJSの ソースコード を見ると、実際はメモリ上に一旦すべて展開されます。 Streamのまま順次処理していく機能も用意されていますが、今回はファイルサイズが小さく、処理が複雑になりそうだったため利用しませんでした。 参考 github.com 最後にテストコードです。 API Routes のテストライブラリは next-test-api-route-handler を利用しています。 // test/api/download.test.ts import fs from 'fs' import path from 'path' import { PassThrough } from 'stream' import { GetObjectCommandOutput } from '@aws-sdk/client-s3' import { sdkStreamMixin } from '@aws-sdk/util-stream-node' import * as ExcelJS from 'exceljs' import { testApiHandler } from 'next-test-api-route-handler' import download from '../../pages/api/download' import * as s3Module from '../../src/aws/s3' const handler: typeof download = download const filePath = path.join ( __dirname , 'download.xlsx' ) const getObjectSpyOn = jest.spyOn ( s3Module , 'getObject' ) const getObject200 = async () : Promise < GetObjectCommandOutput > => { return { Body: sdkStreamMixin ( fs.createReadStream ( filePath )), $metadata: { httpStatusCode: 200 , } , } } const getObject500 = async () : Promise < GetObjectCommandOutput > => { const mockReadable = sdkStreamMixin (new PassThrough ()) mockReadable.emit ( 'error' , new Error ( 'error' )) return { Body: mockReadable , $metadata: { httpStatusCode: 500 , } , } } describe ( 'client-s3' , () => { test ( '200' , async () => { getObjectSpyOn.mockImplementation ( getObject200 ) await testApiHandler ( { handler , test: async ( { fetch } ) => { const res = await fetch ( { method: 'GET' } ) expect ( res. status) .toBe ( 200 ) const workbook = new ExcelJS.Workbook () await workbook.xlsx.read ( res.body ) const worksheet = workbook.getWorksheet ( 'Sheet1' ) expect ( worksheet.getRow ( 1 ) .getCell ( 1 ) .value ) .toBe ( 'テスト' ) } , } ) } ) test ( '500' , async () => { getObjectSpyOn.mockImplementation ( getObject500 ) await testApiHandler ( { handler , test: async ( { fetch } ) => { const res = await fetch ( { method: 'GET' } ) expect ( res. status) .toBe ( 500 ) } , } ) } ) } ) Amazon S3 から取得する箇所をモック化しています。Stream部分には PassThrough を利用しています。 また、 AWS SDK for JavaScript v3のv3.188.0以降では、Stream処理が一部変更になり、Bodyの型が SdkStream<Readable> で返るようになりました。 そのため、 @aws-sdk/util-stream-node にある sdkStreamMixin を利用して、テストコードのモックでも同じ型を返すようにしています。 参考 github.com github.com 以上、Next.jsとTypeScriptを利用して、 Amazon S3 に保存されている Excel をExcelJSで加工してクライアントに返す方法の紹介でした。 電通国際情報サービス Advent Calendar 2022 7日目の明日は、Faisalさんの記事です。お楽しみに! 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 - セキュリティエンジニア(セキュリティ設計) 執筆: @shibata.shunsuke 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター