業界・業務から探す
導入目的・課題から探す
データ・AIについて学ぶ
News
Hakkyについて
ウェビナーコラム
◆トップ【データ基盤】
クラウドDWHを比較
BigQuery Data Transfer Service
Cloud ComposerData Catalog
VPC Service Controls
データの保守運用
AI

執筆者:Handbook編集部

Google Cloud上にVPN環境を構築する

はじめに

この記事では、GCP Marketplaceで提供されているOpenVPN Access ServerのイメージをTerraformから利用して、Google Cloud上にVPN環境を構築する手順を紹介します。

前提

本記事の手順を進めるにあたり、以下の準備が必要です。

  • Google Cloudプロジェクトを所有しており、課金が有効になっていること。
  • Terraform, gcloud cliがローカル環境にインストールされていること。
  • VPNサーバに割り当てるための独自ドメインを所有していること。
  • OpenVPN Access Serverのライセンスを所有していること。(2ユーザまでであれば無償利用可能)

構成

本記事で作成する構成は以下の通りです。

  1. Compute Engine
    OpenVPN Access Serverが動作するCompute Engineを作成します。このVMの起動ディスクには、GCP MarketplaceでOpenVPN Access Serverが提供する特定のOSイメージを使用します。

  2. VPC
    Compute Engineを配置するVPCを作成します。

  3. Elastic IP
    Compute Engineへアタッチします。

構築

terraform

まずはTerraformコードを記述し、必要なリソースを作成します。

  • variables.tf: プロジェクトやリージョンなどの変数を定義
  • provider.tf: GCPプロバイダーの設定
  • network.tf: VPCネットワークとファイアウォールルールの設定
  • iam.tf: サービスアカウントの作成
  • compute_engine.tf: OpenVPNサーバのCompute Engine設定

variables.tf

variable "project" {
  type    = string
  default = "<Google Cloud プロジェクト名>"
}

variable "region" {
  type    = string
  default = "asia-northeast1" #リソースを作成したいリージョン
}

variable "zone" {
  type    = string
  default = "asia-northeast1-a" #リソースを作成したいゾーン
}

provider.tf

terraform {
  required_version = "= 1.9.8"

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "4.31.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "4.32.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "3.4.3"
    }
  }

  backend "local" {
  }

  # GCSでtfstate管理する場合
  /* backend "gcs" {
    bucket = "<tfstate保管用バケット名>"
    prefix = "<tfstate名>"
  } */

}

provider "google" {
  project = var.project
}

provider "google-beta" {
  project = var.project
}

network.tf

resource "google_compute_network" "main" {
  project                         = var.project
  name                            = "${var.project}-vpc"
  routing_mode                    = "REGIONAL"
  auto_create_subnetworks         = false
  delete_default_routes_on_create = false
  enable_ula_internal_ipv6        = false
}

resource "google_compute_subnetwork" "main" {
  project                    = var.project
  region                     = var.region
  name                       = "${var.project}-subnet-asia-northeast1"
  ip_cidr_range              = "10.0.0.0/24"
  network                    = google_compute_network.main.id
  private_ip_google_access   = false
  private_ipv6_google_access = "DISABLE_GOOGLE_ACCESS"
  purpose                    = "PRIVATE"
  stack_type                 = "IPV4_ONLY"

  log_config {
    aggregation_interval = "INTERVAL_15_MIN"
    flow_sampling        = 1
    metadata             = "INCLUDE_ALL_METADATA"
    metadata_fields      = []
  }
}

resource "google_compute_firewall" "allow_ingress_http" {
  project   = var.project
  name      = "${var.project}-ingress-80"
  direction = "INGRESS"
  network   = google_compute_network.main.name
  priority  = 1000
  source_ranges = [
    "0.0.0.0/0",
  ]

  allow {
    ports = [
      "80",
    ]
    protocol = "tcp"
  }
}

resource "google_compute_firewall" "allow_ingress_https" {
  project   = var.project
  name      = "${var.project}-ingress-443"
  direction = "INGRESS"
  network   = google_compute_network.main.name
  priority  = 1000
  source_ranges = [
    "0.0.0.0/0",
  ]

  allow {
    ports = [
      "443",
    ]
    protocol = "tcp"
  }
}

resource "google_compute_firewall" "allow_ingress_ssh" {
  project   = var.project
  name      = "${var.project}-ingress-22"
  direction = "INGRESS"
  network   = google_compute_network.main.name
  priority  = 1000

  source_ranges = [
    "x.x.x.x/x",
  ]

  allow {
    ports = [
      "22",
    ]
    protocol = "tcp"
  }
}

resource "google_compute_firewall" "allow_ingress_openvpn_admin" {
  project   = var.project
  name      = "${var.project}-ingress-943"
  direction = "INGRESS"
  network   = google_compute_network.main.name
  priority  = 1000
  source_ranges = [
    "0.0.0.0/0",
  ]

  allow {
    ports = [
      "943",
    ]
    protocol = "tcp"
  }
}

resource "google_compute_firewall" "allow_ingress_oprnvpn_tunnel" {
  project   = var.project
  name      = "${var.project}-ingress-1194"
  direction = "INGRESS"
  network   = google_compute_network.main.name
  priority  = 1000
  source_ranges = [
    "0.0.0.0/0",
  ]

  allow {
    ports = [
      "1194",
    ]
    protocol = "udp"
  }
}

iam.tf

resource "google_service_account" "openvpn_server" {
  project      = var.project
  account_id   = "openvpn-server"
  display_name = "openvpn-server"
}

compute_engine.tf

resource "google_compute_address" "openvpn_server" {
  project      = var.project
  name         = "openvpn-vm-ip"
  region       = var.region
  address_type = "EXTERNAL"
  network_tier = "PREMIUM"
}

resource "google_compute_instance" "openvpn_server" {
  project      = var.project
  name         = "openvpn-vm"
  machine_type = "e2-medium"
  zone         = var.zone
  can_ip_forward      = true
  deletion_protection = true

  boot_disk {
    auto_delete = true
    device_name = "autogen-vm-tmpl-boot-disk"
    mode        = "READ_WRITE"

    initialize_params {
      image  = "https://www.googleapis.com/compute/v1/projects/mpi-openvpn-access-server-2008/global/images/aspub2113-20231113"
      labels = {}
      size   = 30
      type   = "pd-balanced"
    }
  }

  network_interface {
    network     = google_compute_network.main.self_link
    queue_count = 0
    stack_type  = "IPV4_ONLY"
    subnetwork  = google_compute_subnetwork.main.self_link

    access_config {
      nat_ip       = google_compute_address.openvpn_server.address
      network_tier = "PREMIUM"
    }
  }

  scheduling {
    automatic_restart   = true
    min_node_cpus       = 0
    on_host_maintenance = "MIGRATE"
    preemptible         = false
    provisioning_model  = "STANDARD"
  }

  service_account {
    email = google_service_account.openvpn_server.email
    scopes = [
      "https://www.googleapis.com/auth/devstorage.full_control",
      "https://www.googleapis.com/auth/logging.write",
      "https://www.googleapis.com/auth/monitoring.write",
    ]
  }

  shielded_instance_config {
    enable_integrity_monitoring = true
    enable_secure_boot          = false
    enable_vtpm                 = true
  }

  lifecycle {
    ignore_changes = [
      metadata
    ]
  }
}
note
info
  • コード中のプロジェクトID、リージョン、ゾーン、ネットワーク名などはご自身の環境に合わせて修正してください。

  • source_ranges は、セキュリティの観点からできる限り制限することを強く推奨します。自宅や会社の固定IPなどがあればそれを指定します。

  • 使用するMarketplaceイメージのURIは、時間経過で更新される可能性があります。上記のURIは記事執筆時点のものです。

コードの準備ができたら、terraformを実行します。

terraform init
terraform plan
terraform apply

VPNサーバ設定

OpenVPN Access Server初期設定

Terraformでのリソース作成が完了したら、Conmute EngineへSSHし、OpenVPN Access Serverの初期設定を行います。SSHすると自動的に以下のようなメッセージが流れます。

Welcome to OpenVPN Access Server Appliance 2.11.3

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

(中略)

          OpenVPN Access Server
          Initial Configuration Tool
------------------------------------------------------
OpenVPN Access Server End User License Agreement (OpenVPN-AS EULA)

    1. Copyright Notice: OpenVPN Access Server License;
       Copyright (c) 2009-2022 OpenVPN Inc. All rights reserved.
       "OpenVPN" is a trademark of OpenVPN Inc.

(中略)

Please enter 'yes' to indicate your agreement [no]:

上記質問は利用規約の同意に関するもののため、yesを入力します。 次にこのOpenVPN Access Serverがプライマリノードか聞いてきますが、今回はシングル構成のためEnterを押します。

Will this be the primary Access Server node?
(enter 'no' to configure as a backup or standby node)
> Press ENTER for default [yes]:

その他いくつか質問されますが、基本的にデフォルト設定で問題ないので全てEnterを押してください。

証明書設定

SSL証明書を作成し、OpenVPN Access Serverへ適用します。 今回はlet's encryptの証明書を使用します。

# certbotインストール
apt update
apt install certbot

# 証明書作成
certbot certonly --standalone -d <ドメイン名>

# OpenVPN Access Serverへ適用
sudo sacli -k cs.cert --value_file=/etc/letsencrypt/live/<ドメイン名>/cert.pem ConfigPut 
sudo sacli -k cs.priv_key --value_file=/etc/letsencrypt/live/<ドメイン名>/privkey.pem ConfigPut 
sudo sacli -k cs.ca_bundle --value_file=/etc/letsencrypt/live/<ドメイン名>/fullchain.pem ConfigPut 
sudo sacli start

let's encryptの証明書はデフォルトの有効期限が90日のため、更新処理をcronに設定しておくと便利です。

crontab -e
# 下記行追加
0 0 1 * * sudo certbot renew &amp;&amp; sudo sacli -k cs.cert --value_file=/etc/letsencrypt/live/<ドメイン名>/cert.pem ConfigPut &amp;&amp; sudo sacli -k cs.priv_key --value_file=/etc/letsencrypt/live/<ドメイン名>/privkey.pem ConfigPut &amp;&amp; sudo sacli -k cs.ca_bundle --value_file=/etc/letsencrypt/live/<ドメイン名>/fullchain.pem ConfigPut &amp;&amp; sudo sacli start >> /var/log/openvpn_cert_update.log 2>&amp;1

使い方

OpenVPN Access Serverの準備ができたので、実際にVPNを利用してみます。

ユーザ作成

  1. https://<ドメイン名>:943/admin/user_permissions へアクセスする
  2. 新しく払い出すユーザのメールアドレスをユーザ名として登録する
  3. Allow Auto-loginにチェックを入れる
  4. More Settingsで初期PWを設定する(ユーザに対して連携する)

VPNクライアント設定

  1. https://<ドメイン名>:943 へアクセスする
  2. クライアントアプリをインストールする
  3. 接続プロファイル(autologin)をダウンロードし開く
  4. VPN接続する

異常が無ければこれでVPN接続できている状態となります。

まとめ

この記事では、Terraformを使用してGoogle Cloud上にOpenVPN Access Serverを構築する方法を紹介しました。この方法を活用することで、社内向けのVPN環境を効率的に、かつ手軽に用意できます。Google CloudでのVPN環境構築をご検討の際に、本記事がお役に立てれば幸いです。

参考文献

2025年07月06日に最終更新
読み込み中...