Works / aws-serverless-corporate-site
本サイトは、レンタルサーバーや常時稼働インスタンスを一切使用せず、AWSのサーバーレス・マネージドサービスのみで構成しています。 「どのサービスを使ったか」だけでなく、どのような要件・制約のもとで、なぜその構成を選び、どうIaC化・自動化したかという設計判断を軸に整理しています。 個人開発という制約下で、可用性・セキュリティ・コスト・運用性のバランスを取りながら、年間コスト約1,500円での運用を実現しました。
システム全体を役割ごとのレイヤーに分割して設計しています。各レイヤーはマネージドサービスで構成し、常時稼働サーバーを持たないことを前提にしています。
静的コンテンツをS3に格納し、CloudFrontのエッジキャッシュ経由で配信。S3は非公開とし、OAC経由のアクセスのみを許可。
Route 53でドメインを名前解決し、ACM発行の証明書でTLSを終端。ホストゾーンは別AWSアカウントで管理。
お問い合わせ処理をAPI Gateway (HTTP API) + Lambda (Python 3.12) で構成。リクエスト発生時のみ実行。
LambdaからSES経由でお問い合わせ内容を管理者宛に送信。返信先には送信者アドレスを設定。
全AWSリソースをTerraformで定義。S3リモートステート + State Lockで構成変更を安全に管理。
GitHub ActionsからOIDCでAWSへ認証し、フロント配信・バックエンドのECRプッシュを自動化。
CloudWatch AlarmでLambdaエラー / API Gateway 5xxを監視し、検知時はSNS経由でメール通知。
この構成を設計する際に重視した要件・制約を明示します。以降の設計判断は、すべてこれらの前提から導いています。
主要な構成要素について、【課題・要件】→【選択した構成】→【選択理由】→【得られたメリット】→【トレードオフ】の流れで設計判断を整理します。
SourceArn条件付きでs3:GetObjectのみ許可。assume_roleで操作。ACM証明書はCloudFront要件に合わせus-east-1で発行し、DNS検証レコードをRoute 53に自動作成。POST /contactをLambdaプロキシ統合で処理し、SESでメール送信。AssumeRoleWithWebIdentity。フロント/バックエンドで別ロールを用意し、sub条件でリポジトリを限定。本構成では、以下の理由からサーバーレス・マネージドサービス中心の選択を採用しています。一般的な代替案との対比で、選択の意図を示します。
| 一般的な代替案 | 採用した構成 | この用途で採用した理由 |
|---|---|---|
| S3 Static Website Hosting | S3 + CloudFront + OAC | S3を非公開のままTLS・エッジキャッシュ・独自ドメインを利用でき、セキュリティと配信性能を両立できるため。 |
| EC2 等の常時稼働サーバー | Lambda(サーバーレス) | 低頻度のフォーム処理にはアイドルコストが発生しないサーバーレスが適し、パッチ・スケーリングを委譲できるため。 |
| API Gateway REST API | API Gateway HTTP API | 今回必要な機能はシンプルなPOST処理であり、より低コスト・低レイテンシなHTTP APIで要件を満たせるため。 |
| GitHub Actions に長期アクセスキーを保存 | GitHub Actions OIDC | 長期シークレットを保持せず、短命な一時認証情報でデプロイできるため、漏洩・失効管理のリスクを構造的に排除できる。 |
| DNSを同一アカウントで管理 | Route 53 を別アカウント + assume_role | 共有度の高いDNSをアカウント境界で分離し、権限委譲で必要な操作のみを許可することで影響範囲を限定できるため。 |
セキュリティは特定のレイヤーではなく、配信・認証・権限・通信の各所に組み込んで設計しています。以下はいずれも実際に実装している内容です。
4項目(ACL / ポリシー両面)すべてを有効化し、バケットのパブリック公開を完全に遮断。
SigV4署名でCloudFrontからのみS3オリジンにアクセス。バケットポリシーはSourceArn条件で該当ディストリビューションに限定。
Lambda実行ロールはCloudWatch Logs + SESのみ。デプロイ用ロールはS3 / CloudFront / ECRの必要なアクションに限定。
DNS管理アカウントへは専用ロールへの権限委譲でアクセスし、アカウント境界を維持。
Web Identityフェデレーションで一時認証。信頼ポリシーのsub / aud条件で対象リポジトリを限定。
長期AWSアクセスキーをGitHub Actionsに保存しない。認証はロールARNの参照のみ。
ACM証明書でHTTPS化し、redirect-to-https + 最小プロトコルTLSv1.2_2021を設定。
TerraformステートS3はバージョニング + SSE(AES256)。ロック用DynamoDBはPITRを有効化。
Terraformは単なる構築ツールではなく、「構成を再現可能・レビュー可能な状態に保つ」ための設計の中心に位置づけています。
手動構築ではなくコードで宣言することで、構成の変更履歴・レビュー・再現性を確保し、同じ環境を差分ベースで安全に再構築できるようにするため。全AWSリソース(S3・CloudFront・Route 53・ACM・API Gateway・Lambda・SES・IAM・ECR・DynamoDB・CloudWatch・SNS)をTerraformで定義しています。
ステートファイルはS3バケットに保存し、バージョニングとサーバーサイド暗号化(AES256)を有効化。State Lockによりapplyの競合を防止し、複数実行時のステート破損を回避します。ステート保存用バケットはprevent_destroyで誤削除を防止しています。
3つのAWSプロバイダを定義:デフォルト(ap-northeast-1)、CloudFront/ACM用(us-east-1)、DNS管理アカウント用(assume_role)。各リソースにproviderを明示指定することで、リージョン制約とアカウント分離を1つのコードベースで表現しています。
OIDCで発行された一時認証情報を用いてTerraform適用・デプロイを実行。長期シークレットを持たずにインフラ変更を自動化できます。
デプロイはGitHub Actionsで自動化し、AWSへの認証はOIDCによるシークレットレス方式を採用しています。認証フローは以下の通りです。
frontend/配下の変更をトリガーに、S3同期とCloudFrontキャッシュ無効化(/*)を自動実行。
Goのテスト・ビルド後、Dockerイメージをgithub.shaとlatestタグでECRへプッシュ。
長期アクセスキーは保存・ローテーション・失効管理の運用負担と漏洩リスクを伴います。OIDCではジョブ実行時に短命な一時認証情報を発行し、信頼ポリシーのsub条件で対象リポジトリを限定するため、保持すべき長期シークレットそのものを排除できます。
年間コスト約1,500円は、単なる「安さ」のアピールではなく、 「個人開発という制約下で、必要な可用性・セキュリティ・運用性を維持しながらコストを抑える」という設計思想の結果です。
常時稼働サーバーを持たずサーバーレス・マネージドサービスに寄せることで、アイドル時のコストをほぼゼロに抑えつつ、 TLS・非公開配信・監視・IaC・自動デプロイといった品質要素は妥協せずに維持しています。 コストは「削るもの」ではなく、アーキテクチャ選択の結果として最適化される対象と位置づけています。
「構築して終わり」にしないため、運用負荷を下げる仕組みを設計に組み込んでいます。
Lambdaエラー / API Gateway 5xxをCloudWatch Alarmで監視し、閾値超過時にSNS経由でメール通知。異常を能動的に検知します。
スケーリング・パッチ適用・可用性の維持をAWSマネージドサービスに委ねることで、日常的な運用作業を最小化。
変更はplanによる差分確認 → applyで適用。State Lockとバージョニングで安全に構成を更新できます。
変更対象(frontend / backend)ごとにパイプラインを分離し、手動オペレーションを排除。ヒューマンエラーの余地を減らします。
| カテゴリ | 技術・サービス |
|---|---|
| CDN・静的配信 | Amazon CloudFront, Amazon S3 |
| DNS・SSL | Amazon Route 53, AWS Certificate Manager |
| サーバーレスAPI | Amazon API Gateway (HTTP API), AWS Lambda (Python 3.12) |
| メール | Amazon SES |
| 監視 | Amazon CloudWatch, Amazon SNS |
| コンテナ | Amazon ECR, Docker (マルチステージビルド) |
| IaC | Terraform (マルチプロバイダ・クロスアカウント) |
| CI/CD | GitHub Actions (OIDC認証) |
| バックエンド | Go, Python 3 |
| フロントエンド | HTML5, Tailwind CSS, JavaScript |