[GCC/Terraform] Cloud IAP를 사용하여 외부 IP 주소가 없는 VM 인스턴스에 SSH 연결

TL;DR

  • 여기 창고 참고하세요.
    -> https://github.com/nekoshita/gcp-ssh-to-vm-instance-using-iap-example
  • 이런 사람을 향해

  • 클라우드 IAP
  • 에 대해 알고 싶습니다.
  • GCP의 VPC,subnet,Firewall
  • 을 잘 몰라요.
  • 발판 서버 없이 GCP에 연결하려는 VM 인스턴스
  • terraform으로 GCP를 터치하고자 합니다
  • 해설


    CloudIAP의 구조

  • 이 그림 잘 알겠다.
  • https://cloud.google.com/iap/docs/concepts-overview#how_iap_works
  • GAE 및 GCE 등에서 실행되는 애플리케이션에 대한 액세스를 제어하는 ID 인증 에이전트 서비스
  • 따라서 VM 인스턴스에 외부 IP 주소가 없어도 SSH 연결 가능
  • GCP 프로젝트 CloudIAP의 API 승인


    $ gcloud services enable iap.googleapis.com
    

    네트워크 및 서브넷 작성


    VM 인스턴스를 설정하는 VPC 네트워크 및 서브넷을 만듭니다.
    resource "google_compute_network" "my_network" {
      name                    = "my-network"
      # リージョンごとにサブネットを自動で作成してくれます。今回は使わないのでfalseにします。
      auto_create_subnetworks = false
    }
    
    resource "google_compute_subnetwork" "my_subnetwork" {
      name   = "my-subnetwork"
      region = "asia-northeast1"
    
      # サブネットで使用したい内部IPアドレスの範囲を指定する
      ip_cidr_range = "10.0.0.0/16"
      network       = google_compute_network.my_network.self_link
    
      # CloudLoggingにFlowLogログを出力したい場合は設定する
      log_config {
        metadata = "INCLUDE_ALL_METADATA"
      }
    }
    

    서브넷에서 VM 인스턴스 만들기


    Google은 VM에 인스턴스를 부여하는 서비스 account을 만드는 것을 권장하기 때문에 서비스 account도 정의합니다.
    외부 IP 주소가 추가되지 않으므로 옵션이 추가되지 않습니다access_config.
    resource "google_service_account" "my_service_account_for_bastion" {
      account_id   = "my-service-account-for-bastion"
      display_name = "My Service Account For Bastion"
    }
    
    resource "google_compute_instance" "bastion" {
      # 好きな名前、マシンタイプ、ゾーンに作成してください
      name         = "bastion"
      machine_type = "f1-micro"
      zone         = "asia-northeast1-a"
    
      # Firewallでタグごとにルールを設定したいので、VMインスタンスにタグを設定しておく
      tags = ["bastion-tag"]
    
      # すきなディスクを選んでください
      boot_disk {
        initialize_params {
          image = "debian-cloud/debian-10"
        }
      }
    
      network_interface {
        # 自分で定義したsubnetwork内にインスタンスを起動する
        network    = google_compute_network.my_network.name
        subnetwork = google_compute_subnetwork.my_subnetwork.name
        # 外部IPアドレスを割り振る方法は次の2種類ある。静的外部IPアドレス、エフェメラル外部IPアドレス
        # 今回は外部IPアドレスは割り振らないので、access_configはコメントアウトしておく
        # access_config {}
      }
    
      service_account {
        email  = google_service_account.my_service_account_for_bastion.email
        scopes = ["cloud-platform"]
      }
    
      scheduling {
        # 料金を抑えるためにプリエンプティブルにしておく
        preemptible = true
        # プリエンプティブルの場合は下のオプションが必須
        automatic_restart = false
      }
    }
    

    Firewall 규칙 설정


    CloudIAP를 VM 인스턴스에 연결할 수 있도록 Firewall 규칙을 설정해야 합니다.
    허용해야 할 IP 주소 범위, 프로토콜, 포트가 저희 공식 문서에 기재되어 있습니다.
    https://cloud.google.com/iap/docs/using-tcp-forwarding#create-firewall-rule
    resource "google_compute_firewall" "my_network" {
      name    = "my-network-firewall"
      network = google_compute_network.my_network.name
    
      direction = "INGRESS"
    
      # 通信を許可するprotocolとportを指定する
      allow {
        protocol = "tcp"
        ports    = ["22"]
      }
    
      # 対象のVMインスタンスのタグを指定する
      target_tags = ["bastion-tag"]
      # Cloud IAPのバックエンドIPアドレス範囲を指定する
      # https://cloud.google.com/iap/docs/using-tcp-forwarding#create-firewall-rule
      source_ranges = ["35.235.240.0/20"]
    
      # CloudLoggingにFlowLogログを出力したい場合は設定する
      log_config {
        metadata = "INCLUDE_ALL_METADATA"
      }
    }
    
    

    SSH 연결 사용자에게 Role 부여


    SSH 연결에 필요한 Role은 다음과 같습니다.
    resource "google_project_iam_binding" "access_user" {
      role = google_project_iam_custom_role.my_custom_role.id
    
      members = [
        "user:許可したいGoogleユーザーのメールアドレス",
      ]
    }
    
    resource "google_project_iam_custom_role" "my_custom_role" {
      role_id = "MyCustomRole"
      title   = "My Custom Role"
    
      permissions = [
        # VMインスタンスにSSH接続するのに必要な権限
        "compute.projects.get",
        "compute.instances.get",
        "compute.instances.setMetadata",
        "iam.serviceAccounts.actAs",
        # IAPに必要な権限
        "iap.tunnelInstances.accessViaIAP",
      ]
    }
    
    

    SSH 연결


    -- tunnel-through-iap 옵션을 지정하면 SSH 연결을 위해 CloudIAP를 사용할 수 있습니다.
    $ gcloud beta compute ssh --zone $ZONE $VM_INSTANCE_NAME --project $GCP_PROJECT_ID --tunnel-through-iap
    
    Cloud IAP를 활성화하고 액세스 허가를 받은 경우 Cloud Constore의 SSH 버튼을 통해 로그인할 수 있습니다.

    CloudIAP의 장점과 단점

  • 이점
  • 외부 IP 주소가 없는 VM Instan에 연결할 수 있으므로 유지 관리가 간편해짐
  • 벤치 애플리케이션과 같은 VM 인스턴스에 외부 IP 주소
  • 를 사용할 수 없음
  • 단점
  • Google User 인증을 받은 네트워크가 있으면 SSH 연결
  • 실제 제작 리소스


    차리다


  • 설치Terraform v0.14.5
  • https://releases.hashicorp.com/terraform/
  • Google Cloud Plaatform 만들기 프로젝트
  • https://cloud.google.com/resource-manager/docs/creating-managing-projects
  • GCP Storage Bucket 생성
  • https://cloud.google.com/storage/docs/creating-buckets

  • 설치gcloud CLI
  • https://cloud.google.com/sdk/gcloud
  • 만들어서 SSH에 연결해보도록 하겠습니다.


    #-------------------
    # リポジトリをクローンする
    #-------------------
    $ git clone https://github.com/nekoshita/gcp-ssh-to-vm-instance-using-iap-example
    $ cd gcp-ssh-to-vm-instance-using-iap-example
    
    #-------------------
    # terraform applyしてリソースを作成する
    #-------------------
    $ export GCP_PROJECT_ID="your-gcp-project-id"
    $ export GCS_BUCKET_NAME="your-gcs-bucket-name"
    $ export USER_MAIL="[email protected]"
    $ bin/apply $GCP_PROJECT_ID $GCS_BUCKET_NAME $USER_MAIL
    
    #-------------------
    # SSH接続する
    #-------------------
    $ export ZONE="asia-northeast1-a"
    $ export VM_INSTANCE_NAME="bastion"
    # GCPのprojectを作成したgoogleアカウントでログインする(すでにログインしてる場合は不要)
    $ gcloud auth login
    $ gcloud beta compute ssh --zone $ZONE $VM_INSTANCE_NAME --project $GCP_PROJECT_ID --tunnel-through-iap
    
    #-------------------
    # 最後にリソースの削除をお忘れなく!
    #-------------------
    $ export GCP_PROJECT_ID="your-gcp-project-id"
    $ export GCS_BUCKET_NAME="your-gcs-bucket-name"
    $ export USER_MAIL="[email protected]"
    $ bin/destroy $GCP_PROJECT_ID $GCS_BUCKET_NAME $USER_MAIL
    

    최후


    공식 문서를 바탕으로 이해한 줄 알았는데 제 인식이 틀리면 제 잘못을 지적해 주시면 기쁩니다!

    좋은 웹페이지 즐겨찾기