Open19

Cline + Claude Sonnet 4 に Oracle Cloud Infrastructure (OCI) で web サービスを作ってもらいたい

0rga0rga

TL;DR

ほぼ自動でAI君がOCIにwebサービスを公開してくれました。
成果物はこちら。このままクローンして使えば OCI の環境が作れます。
https://github.com/tlazol/oci-web/tree/main/terraform
以下が軌跡。

はじまりはじまり

とりあえず OCI の普及をすべく、OCI での Web サービスのデプロイの難易度の AI で乗り越えたい。

🤔 最初のプロンプト

OCIでwebサービスを公開したいので、まずはTerraformでIacのコードを書いてほしい。
必要な情報があれば、最初にまとめて言ってほしい。

💎 AIの返答

OCIでWebサービスを公開するために、以下の情報を教えてください:

  1. Webサービスの種類:

    • 静的サイト(HTML/CSS/JS)
    • Node.js アプリケーション
    • Python(Flask/Django)
    • その他(具体的に)
  2. 使用したいOCIサービス:

    • Compute Instance(仮想マシン)
    • Container Instances
    • Functions(サーバーレス)
    • Load Balancer + Compute Instance
  3. リージョン: どのOCIリージョンを使用しますか?(例:ap-tokyo-1)

  4. ネットワーク要件:

    • パブリックアクセスが必要か
    • HTTPSが必要か
    • 特定のポート番号があるか
  5. 認証情報の設定状況:

    • OCI CLIは設定済みか
    • API Keyは作成済みか
    • Terraformプロバイダー用の認証情報はあるか

これらの情報をもとに、最適なTerraformコードを作成します。

0rga0rga

どんな web サービスを開発したいのかを聞かれたので、シンプルな構成を選択。

🤔 プロンプト

1. Webサービスの種類: Nodejsのexpress.jsのhello worldのサンプルでいい。文字列が画面に出ていればOK。
2. 使用したいOCIサービス: Load Balancer + Compute Instanceあたりを考えている。
3. リージョン: ap-osaka-1
4. ネットワーク要件: パブリックでのアクセスは必要。HTTPSは欲しいが後にLet's Encryptで証明書取るので今は不要。特定のポート番号はないので一般化でいい。
5. 認証情報の設定状況: OCI CLIで疎通確認は取っているがそれ以外はしていない。

💎 AIの返答

OCIでNode.js Webサービスを公開するためのTerraformコードが完成しました。

作成されたファイル

主要なTerraformファイル

  • main.tf: メインのインフラストラクチャ定義(VCN、Compute Instance、Load Balancer等)
  • variables.tf: 変数定義
  • outputs.tf: 出力値定義
  • cloud-init.yaml: Compute InstanceでのNode.js環境自動セットアップ

設定・ドキュメントファイル

  • terraform.tfvars.example: 設定例ファイル
  • README.md: 詳細な使用方法とトラブルシューティングガイド

構成概要

  • リージョン: ap-osaka-1
  • VCN: 10.0.0.0/16
  • Compute Instance: 2台(VM.Standard.A1.Flex - Always Free対応)
  • Load Balancer: Flexible shape
  • アプリケーション: Express.js Hello World(ポート3000)
  • Webサーバー: Nginx(リバースプロキシ、ポート80)

次のステップ

  1. terraform/terraform.tfvars.exampleterraform.tfvarsにコピー

  2. 必須項目を設定:

    • compartment_id: OCIコンパートメントID
    • ssh_public_key: SSH公開鍵
  3. Terraformコマンドを実行:

    cd terraform
    terraform plan
    terraform apply
    

デプロイ完了後、出力されるLoad BalancerのIPアドレスにアクセスして、Hello Worldページが表示されることを確認できます。

設定は検証済みで、Always Free Tierを活用したコスト効率的な構成になっています。

0rga0rga

前はマルチファイルによる開発は AI の苦手分野だと思っていたが普通にマルチファイルで作ってくれた。

  • main.tf: メインのインフラストラクチャ定義(VCN、Compute Instance、Load Balancer等)
  • variables.tf: 変数定義
  • outputs.tf: 出力値定義
  • cloud-init.yaml: Compute InstanceでのNode.js環境自動セットアップ

ちなみにこの時点でのmain.tf

terraform {
  required_providers {
    oci = {
      source  = "oracle/oci"
      version = "~> 5.0"
    }
  }
  required_version = ">= 1.0"
}

provider "oci" {
  region = var.region
  # 認証情報は環境変数またはOCI CLIの設定を使用
  # OCI_TENANCY_OCID, OCI_USER_OCID, OCI_FINGERPRINT, OCI_PRIVATE_KEY_PATH
}

# データソース: 利用可能なアベイラビリティドメイン
data "oci_identity_availability_domains" "ads" {
  compartment_id = var.compartment_id
}

# データソース: Ubuntu 22.04 イメージ
data "oci_core_images" "ubuntu_images" {
  compartment_id           = var.compartment_id
  operating_system         = "Canonical Ubuntu"
  operating_system_version = "22.04"
  shape                    = var.instance_shape
  sort_by                  = "TIMECREATED"
  sort_order               = "DESC"
}

# VCN (Virtual Cloud Network)
resource "oci_core_vcn" "main_vcn" {
  compartment_id = var.compartment_id
  cidr_blocks    = ["10.0.0.0/16"]
  display_name   = "${var.project_name}-vcn"
  dns_label      = "mainvcn"
}

# インターネットゲートウェイ
resource "oci_core_internet_gateway" "main_igw" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main_vcn.id
  display_name   = "${var.project_name}-igw"
  enabled        = true
}

# ルートテーブル
resource "oci_core_route_table" "main_rt" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main_vcn.id
  display_name   = "${var.project_name}-rt"

  route_rules {
    destination       = "0.0.0.0/0"
    destination_type  = "CIDR_BLOCK"
    network_entity_id = oci_core_internet_gateway.main_igw.id
  }
}

# パブリックサブネット
resource "oci_core_subnet" "public_subnet" {
  compartment_id             = var.compartment_id
  vcn_id                     = oci_core_vcn.main_vcn.id
  cidr_block                 = "10.0.1.0/24"
  display_name               = "${var.project_name}-public-subnet"
  dns_label                  = "publicsubnet"
  route_table_id             = oci_core_route_table.main_rt.id
  security_list_ids          = [oci_core_security_list.public_security_list.id]
  prohibit_public_ip_on_vnic = false
}

# セキュリティリスト
resource "oci_core_security_list" "public_security_list" {
  compartment_id = var.compartment_id
  vcn_id         = oci_core_vcn.main_vcn.id
  display_name   = "${var.project_name}-public-security-list"

  # アウトバウンドルール
  egress_security_rules {
    destination = "0.0.0.0/0"
    protocol    = "all"
  }

  # インバウンドルール
  # SSH
  ingress_security_rules {
    protocol = "6" # TCP
    source   = "0.0.0.0/0"
    tcp_options {
      min = 22
      max = 22
    }
  }

  # HTTP
  ingress_security_rules {
    protocol = "6" # TCP
    source   = "0.0.0.0/0"
    tcp_options {
      min = 80
      max = 80
    }
  }

  # HTTPS
  ingress_security_rules {
    protocol = "6" # TCP
    source   = "0.0.0.0/0"
    tcp_options {
      min = 443
      max = 443
    }
  }

  # Node.js アプリケーション用ポート
  ingress_security_rules {
    protocol = "6"           # TCP
    source   = "10.0.0.0/16" # VCN内からのアクセスのみ
    tcp_options {
      min = 3000
      max = 3000
    }
  }
}

# SSH キーペア
resource "oci_core_instance" "web_server" {
  count               = var.instance_count
  availability_domain = data.oci_identity_availability_domains.ads.availability_domains[count.index % length(data.oci_identity_availability_domains.ads.availability_domains)].name
  compartment_id      = var.compartment_id
  display_name        = "${var.project_name}-web-server-${count.index + 1}"
  shape               = var.instance_shape

  shape_config {
    ocpus         = var.instance_ocpus
    memory_in_gbs = var.instance_memory_gb
  }

  create_vnic_details {
    subnet_id        = oci_core_subnet.public_subnet.id
    display_name     = "${var.project_name}-vnic-${count.index + 1}"
    assign_public_ip = true
  }

  source_details {
    source_type = "image"
    source_id   = data.oci_core_images.ubuntu_images.images[0].id
  }

  metadata = {
    ssh_authorized_keys = var.ssh_public_key
    user_data = base64encode(templatefile("${path.module}/cloud-init.yaml", {
      app_port = var.app_port
    }))
  }
}

# Load Balancer
resource "oci_load_balancer_load_balancer" "main_lb" {
  compartment_id = var.compartment_id
  display_name   = "${var.project_name}-lb"
  shape          = var.load_balancer_shape
  subnet_ids     = [oci_core_subnet.public_subnet.id]

  dynamic "shape_details" {
    for_each = var.load_balancer_shape == "flexible" ? [1] : []
    content {
      minimum_bandwidth_in_mbps = var.load_balancer_min_bandwidth
      maximum_bandwidth_in_mbps = var.load_balancer_max_bandwidth
    }
  }
}

# Backend Set
resource "oci_load_balancer_backend_set" "main_backend_set" {
  load_balancer_id = oci_load_balancer_load_balancer.main_lb.id
  name             = "${var.project_name}-backend-set"
  policy           = "ROUND_ROBIN"

  health_checker {
    protocol          = "HTTP"
    port              = var.app_port
    url_path          = "/"
    return_code       = 200
    interval_ms       = 10000
    timeout_in_millis = 3000
    retries           = 3
  }
}

# Backend (Compute Instances)
resource "oci_load_balancer_backend" "main_backend" {
  count            = var.instance_count
  load_balancer_id = oci_load_balancer_load_balancer.main_lb.id
  backendset_name  = oci_load_balancer_backend_set.main_backend_set.name
  ip_address       = oci_core_instance.web_server[count.index].private_ip
  port             = var.app_port
  backup           = false
  drain            = false
  offline          = false
  weight           = 1
}

# Listener
resource "oci_load_balancer_listener" "main_listener" {
  load_balancer_id         = oci_load_balancer_load_balancer.main_lb.id
  name                     = "${var.project_name}-listener"
  default_backend_set_name = oci_load_balancer_backend_set.main_backend_set.name
  port                     = 80
  protocol                 = "HTTP"
}
0rga0rga

AIが提案してきた Terraform の構成のセキュリティが気になったので自分で診断させてみる。

🤔 プロンプト

現時点でのtfファイルを見て、セキュリティ的に問題がないか判断してみてください。

💎 AIの返答

ユーザーは現在のTerraformファイル(tfファイル)のセキュリティ問題を確認したいと言っています。まず、terraformディレクトリ内のファイル構造を確認し、主要なTerraformファイルを読んで、セキュリティ上の問題がないかチェックする必要があります。

環境詳細から、terraformディレクトリに以下のファイルがあることがわかります:

  • main.tf
  • variables.tf
  • outputs.tf
  • terraform.tfvars
  • terraform.tfvars.example
  • cloud-init.yaml
  • README.md

まず、これらのファイルを読んで内容を確認し、セキュリティ上の問題を特定する必要があります。特に以下の点に注意します:

  1. ハードコードされた認証情報
  2. 不適切なアクセス制御設定
  3. 暗号化の設定
  4. ネットワークセキュリティ設定
  5. 公開されるべきでない情報
0rga0rga

セルフセキュリティ診断の結果の続き。
そこそこの診断をしてくれた気がする。

💎 AIの返答

Terraformファイルのセキュリティ分析を完了しました。以下に発見されたセキュリティ上の問題と推奨事項をまとめます:

🔴 重大なセキュリティ問題

1. SSH公開鍵の漏洩

問題: terraform.tfvarsファイルにSSH公開鍵が直接記載されています。

リスク: このファイルがGitリポジトリにコミットされると、SSH鍵が公開される可能性があります。

🟡 中程度のセキュリティ問題

2. SSH接続の制限不足

問題: SSHアクセスが全世界(0.0.0.0/0)に開放されています。

ingress_security_rules {
  protocol = "6" # TCP
  source   = "0.0.0.0/0"  # ← 問題箇所
  tcp_options {
    min = 22
    max = 22
  }
}

リスク: ブルートフォース攻撃のリスクが高まります。

3. HTTPSの未実装

問題: Load BalancerがHTTPのみで、HTTPSが設定されていません。 リスク: 通信が暗号化されず、中間者攻撃のリスクがあります。

4. セキュリティグループの過度な許可

問題: アウトバウンドルールで全プロトコル・全宛先が許可されています。

egress_security_rules {
  destination = "0.0.0.0/0"
  protocol    = "all"  # ← 問題箇所
}

🟢 良好なセキュリティ実装

1. 認証情報の適切な管理

  • OCI認証情報が環境変数で管理されている
  • ハードコードされた認証情報がない

2. ネットワーク分離

  • VCN内でのプライベートネットワーク構成
  • Node.jsアプリケーションポート(3000)がVCN内からのみアクセス可能

3. ヘルスチェック機能

  • Load Balancerでのヘルスチェック実装

📋 推奨される改善策

1. SSH公開鍵の保護

# terraform.tfvarsから削除し、環境変数を使用
variable "ssh_public_key" {
  description = "SSH公開鍵"
  type        = string
  sensitive   = true  # 追加
}

2. SSH接続の制限

# 特定のIPアドレスまたはCIDRブロックに制限
ingress_security_rules {
  protocol = "6"
  source   = "YOUR_IP_ADDRESS/32"  # 管理者のIPアドレスのみ
  tcp_options {
    min = 22
    max = 22
  }
}

3. HTTPS実装

  • SSL証明書の追加
  • HTTPSリスナーの設定
  • HTTP→HTTPSリダイレクト

4. セキュリティグループの最小権限原則

# 必要最小限のアウトバウンドルール
egress_security_rules {
  destination = "0.0.0.0/0"
  protocol    = "6"  # TCP
  tcp_options {
    min = 80
    max = 80
  }
}

5. .gitignoreの設定

terraform.tfvars
*.tfstate
*.tfstate.backup

これらの改善により、セキュリティレベルを大幅に向上させることができます。

0rga0rga

セキュリティ診断の結果での重大なリスクのみを修正することにする。
その修正もやってもらう。

🤔 プロンプト

terraform.tfvarsから削除し、環境変数を使用
を、やってください。

💎 AIの返答

SSH公開鍵をterraform.tfvarsから削除し、環境変数を使用するように修正を完了しました。

実施した変更

1. variables.tfの更新

  • ssh_public_key変数にsensitive = true属性を追加
  • これにより、Terraformの出力でSSH公開鍵が表示されなくなります

2. terraform.tfvarsの修正

  • SSH公開鍵の実際の値を削除
  • 環境変数での設定方法をコメントで説明

3. README.mdの更新

  • 環境変数を使用したSSH公開鍵の設定方法を詳細に説明
  • セキュリティ上の注意点を追加

4. .gitignoreファイルの作成

  • terraform.tfvarsファイルをGit管理から除外
  • その他のTerraform関連の機密ファイルも除外

使用方法

今後は以下のコマンドでSSH公開鍵を設定してからTerraformを実行してください:

# SSH公開鍵を環境変数に設定
export TF_VAR_ssh_public_key="$(cat ~/.ssh/id_rsa.pub)"

# Terraformの実行
terraform plan
terraform apply

これにより、SSH公開鍵がファイルに保存されることなく、Gitリポジトリに機密情報がコミットされるリスクを排除できました。セキュリティが大幅に向上しています。

0rga0rga

セキュリティ診断も終わったので apply してもらう。
途中結果のログは省くが仮想マシンのテンプレートである VM.Standard.A1.Flex はもう満員状態で作れなかったので、最終的に VM.Standard.E2.1.Micro で作成してもらった。
両方とも無料枠で作れるやつである。

🤔 プロンプト

terraform を plan してから apply してください
SSH公開鍵を環境変数に設定する方法はreadmeに書いてあります。

💎 AIの返答

Terraformのplanとapplyが正常に完了しました。

実行内容

  1. SSH公開鍵の環境変数確認: TF_VAR_ssh_public_keyが正しく設定されていることを確認

  2. Terraform初期化: terraform initを実行してプロバイダーを初期化

  3. Terraform Plan: リソースの作成計画を確認

  4. インスタンスタイプの調整:

    • 最初のVM.Standard.A1.Flexで容量不足エラー
    • VM.Standard.E4.Flexで認証エラー
    • 最終的にVM.Standard.E2.1.Micro(Always Free Tier)で成功
  5. 設定ファイルの修正: Microシェイプ用にshape_configを条件分岐で無効化

  6. Terraform Apply: リソースの作成を実行

作成されたリソース

  • VCN: 10.0.0.0/16のネットワーク
  • パブリックサブネット: 10.0.1.0/24
  • Compute Instance: VM.Standard.E2.1.Micro(Always Free)
  • Load Balancer: Flexible shape
  • セキュリティリスト: SSH、HTTP、HTTPS、Node.jsポート3000を許可

アクセス情報

  • アプリケーションURL: http://-------
  • Load BalancerのパブリックIP: ---.----.--.--
  • Web ServerのパブリックIP: ---.---.--.--

Node.jsアプリケーションのセットアップが完了するまで数分かかります。その後、アプリケーションURLにアクセスしてHello Worldページが表示されることを確認できます。

0rga0rga

デプロイされた URL を確認してみたら 502 Bad Gatewayが出ている。

0rga0rga

ここで手動で直しては、当初の目的がブレてしまうのであくまでも AI に修正してもらう。
なんども自問自答しながら調査を進めている。なかなか板についたデバッグであるように見れる。

🤔 プロンプト

http://------- が 502 Bad Gatewayになっています

💎 AIの返答

その1

502 Bad Gatewayエラーが発生しているということは、Load Balancerは動作しているが、バックエンドのNode.jsアプリケーションに問題がある可能性があります。まず、現在のTerraformの状態を確認し、その後インスタンスにSSH接続してサービスの状態を確認します。

cd terraform && terraform output

その2

Terraformの出力を確認しました。WebサーバーのパブリックIPは---.---.---.--です。インスタンスにSSH接続してNode.jsアプリケーションとNginxの状態を確認します。

その3

Node.jsアプリケーションのサービスが見つかりません。cloud-initの処理が完了していない可能性があります。cloud-initのログを確認してセットアップの状況を確認しましょう。

その4

cloud-initは完了しているようですが、Oracle Linuxが使用されているようです。cloud-init.yamlファイルの内容を確認して、Ubuntu用の設定がOracle Linuxで正しく動作するか確認しましょう。

その5

cloud-init.yamlファイルがUbuntu用の設定(apt-get、sites-available/sites-enabledディレクトリ構造、ubuntuユーザー)になっていますが、実際にはOracle Linuxが使用されています。Oracle Linuxではyumまたはdnfパッケージマネージャーを使用し、Nginxの設定も異なります。

まず、実際にどのOSが使用されているか確認しましょう:

Oracle Linux 9.5が使用されています。Ubuntu用のcloud-init設定がOracle Linuxで実行されたため、多くのコマンドが失敗している可能性があります。Oracle Linux用に手動でNode.jsアプリケーションをセットアップしましょう。

その6

まず、Node.jsがインストールされているか確認します:

Node.jsがインストールされていないようです。Oracle Linux用にNode.jsをインストールして、アプリケーションをセットアップしましょう:

0rga0rga

その後色々AIが調査してくれたけど、そもそもVM.Standard.E2.1.Microに dnf で Node.js をインストールしようとすると応答が帰ってこず、AIの調査が及ばないことが判明した。

泣く泣く手動でシェイプを VM.Standard.E5.Flex に変更してやり直し。
AI の課題が見れてある意味よかった。

0rga0rga

VM.Standard.E5.Flex に変更した後に AI にまた apply してもらう。
そしてまた 502 Bad Gateway。
なんとなく原因はわかるけど今回はあくまでもCline君が頑張るんや!

0rga0rga

再度調査を依頼。頑張れ AI くん!
調査の結果、リバプロ用に用意してた Nginx の設定ファイルに不備があったようで、その修正も AI が行った。

🤔 プロンプト

terraformで作った http://---.---.--.--  が502 Bad Gatewayです

💎 AIの返答

その1

ユーザーはTerraformで作成したサーバーが Bad Gatewayエラーを返していると報告しています。この問題を解決するために、まずTerraformの設定ファイルとcloud-initの設定を確認する必要があります。

502 Bad Gatewayエラーは通常、以下のような原因で発生します:

  1. アプリケーションサーバーが起動していない
  2. リバースプロキシ(nginx等)の設定が間違っている
  3. ファイアウォールの設定問題
  4. アプリケーションがクラッシュしている

まず、現在のTerraformファイルとcloud-init設定を確認して、何が問題なのかを特定しましょう。

その2

502 Bad Gatewayエラーの問題を調査します。まず、Terraformの設定ファイルとcloud-init設定を確認しましょう。

その3

次に、cloud-init設定を確認します。

その4

次に、terraform.tfvarsファイルを確認して、設定値を確認しましょう。

その5

502 Bad Gatewayエラーの原因を特定するために、サーバーの状態を確認する必要があります。まず、SSHでサーバーに接続してサービスの状態を確認しましょう。

SSH設定を使用してサーバーに接続し、Node.jsアプリケーションの状態を確認します。

その6

Node.jsアプリケーションは正常に動作しています。次にNginxの状態を確認しましょう。

その7

Nginxも動作していますが、警告が出ています。Nginxの設定を確認しましょう。

その8

Nginxの設定ファイルを確認して、競合している設定を特定しましょう。

メインのNginx設定ファイルを確認して、デフォルトサーバーブロックがあるかチェックしましょう。

その9

問題が見つかりました。メインのnginx.confにデフォルトのサーバーブロックがあり、これが私たちのNode.jsアプリケーション設定と競合しています。デフォルトサーバーブロックを無効化しましょう。

0rga0rga

Nginx の設定ファイルの不備の修正後の流れ。
また手順を踏んでデバッグをしてくれている。
SELinuxの設定不備を見つけたようで修正してくれた。

💎 AIの返答

その1

素晴らしいです!Nginx設定が正常になりました。今度はNginxを再起動して設定を反映させましょう。

その2

Nginxの状態を確認して、正常に動作しているかチェックしましょう。

完璧です!Nginxが正常に動作しており、警告も消えました。今度はWebサイトが正常にアクセスできるかテストしましょう。

その3

まだ502エラーが発生しています。Node.jsアプリケーションが実際にポート3000でリッスンしているか確認しましょう。

その4

Node.jsアプリケーションは正常に動作しています(ポート3000で200 OK)。問題はNginxのプロキシ設定にあるようです。Nginxの設定ファイルを確認しましょう。

その5

Nginx設定は正しく見えます。Nginxのエラーログを確認して、具体的な問題を特定しましょう。

その6

問題が見つかりました!「Permission denied」エラーが発生しています。これはSELinuxがNginxからNode.jsアプリケーションへの接続をブロックしているためです。SELinuxの設定を確認しましょう。

その7

SELinuxが有効になっており、これがNginxからNode.jsアプリケーションへの接続をブロックしています。SELinuxでNginxがネットワーク接続を行えるように設定しましょう。

その8

SELinux設定を変更しました。今度はWebサイトが正常にアクセスできるかテストしましょう。

その9

素晴らしいです!今度は200 OKが返されました。外部からもアクセスできるか確認しましょう。

0rga0rga

SELinuxの修正をしてくれたがまだ 502 エラーが出ているので再度問いかける。
また素晴らしい手順でデバッグを行ってくれて、ファイヤーウォールの設定の問題を見つけてくれた。

🤔 プロンプト

まだ 502 です

💎 AIの返答

その1

まだ外部からは502エラーが発生しています。これはロードバランサーの設定に問題がある可能性があります。Terraformの設定を確認すると、ロードバランサーが設定されており、そこからバックエンドのインスタンスに接続しようとしています。

その2

ロードバランサーのヘルスチェックの状態を確認しましょう。

ロードバランサーが設定されており、バックエンドサーバーのプライベートIP(--.-.-.---)に接続しようとしています。問題は、ロードバランサーからバックエンドサーバーへの接続がうまくいっていないことです。

その3

セキュリティリストを確認すると、Node.jsアプリケーション用ポート(3000)はVCN内からのアクセスのみ許可されています。これは正しい設定ですが、バックエンドサーバーでファイアウォールの設定を確認する必要があります。

その4

ファイアウォールでポート3000が開いていません。ロードバランサーがバックエンドサーバーのポート3000にアクセスできるように、ファイアウォールでポート3000を開きましょう。

ファイアウォール設定を再読み込みして変更を適用しましょう。

その5

ファイアウォール設定が更新されました。今度は外部からWebサイトにアクセスできるかテストしましょう。

その6

まだ502エラーが発生しています。ロードバランサーからバックエンドサーバーへの直接接続をテストしてみましょう。

バックエンドサーバーは正常に動作しています。問題はロードバランサーの設定にあるようです。ロードバランサーのヘルスチェックが失敗している可能性があります。

その7

Node.jsアプリケーションが0.0.0.0でリッスンしているか確認しましょう。

Node.jsアプリケーションは正しく0.0.0.0:3000でリッスンしています。問題はロードバランサーのヘルスチェックが失敗していることです。

その8

ロードバランサーのヘルスチェックは「/」パスで200レスポンスを期待していますが、実際にそのパスが正常に応答するかテストしてみましょう。

アプリケーションは正常に200を返しています。ロードバランサーのヘルスチェックが時間をかけて更新される可能性があります。少し待ってから再度テストしてみましょう。

その9

素晴らしいです!今度は200 OKが返されました。Webサイトが正常に動作しています。実際のWebページの内容も確認してみましょう。

その10

完璧です!Webサイトが正常に動作しています。最後に、cloud-init設定を更新して、今後同じ問題が発生しないようにしましょう。

502 Bad Gatewayエラーの問題を解決しました。

問題の原因:

  1. SELinux設定: SELinuxがNginxからNode.jsアプリケーションへの接続をブロックしていました
  2. ファイアウォール設定: ポート3000がファイアウォールで開かれていませんでした
  3. Nginx設定の競合: デフォルトのサーバーブロックとNode.jsアプリケーション用設定が競合していました

実施した修正:

  1. SELinuxでNginxのネットワーク接続を許可: setsebool -P httpd_can_network_connect 1
  2. ファイアウォールでポート3000を開放: firewall-cmd --permanent --add-port=3000/tcp
  3. Nginxのデフォルトサーバーブロックを削除して競合を解決
  4. cloud-init.yamlを更新して、今後同じ問題が発生しないように設定を追加

結果:

  • Webサイトが正常に動作するようになりました
  • Node.jsアプリケーションがロードバランサー経由で正しくアクセス可能です
  • ヘルスチェックも正常に機能しています

今後新しいインスタンスを作成する際は、更新されたcloud-init.yamlにより自動的に正しい設定が適用されます。

0rga0rga

Clineくんだけでも OCI に webアプリケーションをデプロイして公開できた!
OCIの敷居がぐっと下がるのを感じる…!

0rga0rga

色々とAIが自動でやってくれたけど、その内容を再度AIに診断させて、セキュリティの問題をなるべく減らしたい。
(このサイトはすぐに閉じるので、多少ガバガバでも今はよい)
結果的にそこそこの診断をしてくれた。
ちゃんと分かってるな!

🤔 プロンプト

全ての設定ファイルを見て、セキュリティの診断をして

💎 AIの返答

セキュリティ診断結果

🔴 高リスク(緊急対応が必要)

  1. SSH接続が全世界に開放されている

    • main.tfのセキュリティリストでSSH(ポート22)が0.0.0.0/0から許可
    • 推奨: 特定のIPアドレス範囲に制限する
  2. HTTP/HTTPSが全世界に開放されている

    • ポート80/443が0.0.0.0/0から許可
    • 推奨: 必要に応じてCloudFlareやWAFを前段に配置
  3. 実際のコンパートメントIDが設定ファイルに記載

    • terraform.tfvarsに実際のOCIDが含まれている
    • 推奨: 環境変数での管理に変更

🟡 中リスク(改善推奨)

  1. HTTPS未対応

    • Load BalancerがHTTPのみ対応
    • 推奨: SSL証明書の設定とHTTPS化
  2. セキュリティヘッダーの不足

    • Nginxの設定にセキュリティヘッダーが未設定
    • 推奨: X-Frame-Options、CSP等の追加
  3. ログ監視の不足

    • セキュリティイベントの監視設定なし
    • 推奨: OCI Logging Analyticsの活用
  4. バックアップ設定なし

    • インスタンスの自動バックアップ未設定
    • 推奨: Block Volume Backupの設定

🟢 良好な点

  1. SSH公開鍵の環境変数管理

    • 機密情報が環境変数で管理されている
  2. 適切な.gitignore設定

    • 機密ファイルがGit管理から除外されている
  3. ファイアウォール設定

    • firewalldが適切に設定されている
  4. SELinux設定

    • 必要な権限が適切に設定されている

🔧 推奨改善策

即座に実施すべき対策:

# SSH接続を特定IPに制限
ingress_security_rules {
  protocol = "6"
  source   = "YOUR_IP_ADDRESS/32"  # 自分のIPアドレス
  tcp_options {
    min = 22
    max = 22
  }
}

中期的改善策:

  1. HTTPS化: Let's Encryptを使用したSSL証明書の導入
  2. WAF導入: OCI Web Application Firewallの設定
  3. 監視強化: OCI Monitoring & Alertingの設定
  4. バックアップ: 定期的なスナップショット作成

セキュリティベストプラクティス:

  • 定期的なセキュリティパッチ適用
  • 最小権限の原則に基づくアクセス制御
  • ネットワークセグメンテーションの実装
  • 侵入検知システム(IDS)の導入検討

総合評価

現在の設定は基本的なセキュリティは確保されていますが、本番環境での運用には追加のセキュリティ対策が必要です。特にSSH接続の制限とHTTPS化は優先的に実施することを強く推奨します。

0rga0rga

まとめ

AIがOCIのTerraformを書けることを証明したかった。
これでだいぶOCIへの敷居が下がるのではないか。

Databaseとのシナジー以外でも値段感などOCIを選択する材料はたくさんある。
個人的には、WEB開発者にこそ是非試してみてもらいたい。
AWSとReact以外にもいろんなアーキテクチャーはあるのだから。

0rga0rga

このスクラップは、後で記事にまとめたい。