LoginSignup
13
12

More than 5 years have passed since last update.

VPN設定をしたセキュアなインスタンスをterraform, Ansible, Dockerで構築

Last updated at Posted at 2016-06-15

Screen Shot 2016-06-08 at 5.04.54 PM.png

AWSの運用者は上記のような構成を作成してくれと頼まれることが多いのではないでしょうか?
特にDatabaseのインスタンスはprivateなSubnetで管理してセキュアな環境でアクセス管理をしたい人も多いはず。
今回はterraformを用いてインスタンスの自動設定から、VPNの設定、AnsibleによるVPN設定用のコンテナの作成からVPNを用いた接続まで行ってみます。
ちなみに著者はAWSのインフラ周りが専門ではありません。

対象読者

  • インフラ担当者
  • アプリ担当だけどリソースの関係でインフラもしないといけない人

この記事を読んで得られること

  • プライベートな環境とパブリックな環境に分けてインスタンスを分けて作成する方法
  • Dockerコンテナを用いてVPNを用いる方法
  • terraformでAWSインスタンスを自動生成する方法。
  • カジュアルに研究開発の環境を作成したい人

作成手順

参考サイト

VPN

Screen Shot 2016-06-11 at 5.17.34 PM.png

VPNの設定にはOpenVPNを使用します。
OpenVPNの下記の特徴があります。

  • セキュアなアクセス
  • どこにいてもアクセス可能
  • エンタープライズな環境でも使用されている

terraform

Screen Shot 2016-03-01 at 6.26.13.jpg

terraformはクラウド環境の構築の自動ツールです。
今回はAWSの環境構築を自動化しています。

Mac環境だと下記のコマンドでインストールできます。

brew update && brew install terraform

インストールしたterraformのPATHを通して、実行すると下記のコマンドが確認できます。

usage: terraform [--version] [--help] <command> [<args>]

Available commands are:
    apply      Builds or changes infrastructure
    destroy    Destroy Terraform-managed infrastructure
    get        Download and install modules for the configuration
    graph      Create a visual graph of Terraform resources
    init       Initializes Terraform configuration from a module
    output     Read an output from a state file
    plan       Generate and show an execution plan
    pull       Refreshes the local state copy from the remote server
    push       Uploads the the local state to the remote server
    refresh    Update local state file against real resources
    remote     Configures remote state management
    show       Inspect Terraform state or plan
    version    Prints the Terraform version

今回の記事で使用するのは3つです。

文法チェック

terraform plan

インスタンス作成

terraform plan

インスタンス破棄

terraform destroy

terraform初心者の方は下記をご覧下さい。

Step by stepで学ぶTerraformによる監視付きAWS構築

Ansible

Screen Shot 2016-03-01 at 6.26.13.jpg

Ansibleの初心者は公式ドキュメントと下記をご覧になってから読まれた方が良いです。

インフラ自動構築エンジン "Ansible"の勘所を1日でつかむ ~基礎入門編~

Docker

Screen Shot 2016-03-01 at 6.26.13.jpg

Dockerはアプリケーション実行環境を抽象化する技術の一つです。VMWareとの違いは実行環境の軽さによるポータビリティがあります。
今回、Dockerを使用する理由は下記です。

 1:同一性、ポータビリティにより、新規参入者にすぐに環境の提供が行える。
 2:今回、使用するElastic Searchの設定を部署ごとにコンテナを用意して変えるなどがしやすい

Dockerに関して詳細を知りたい方は下記をご覧ください。

Docker入門 - 基礎編 いまから始めるDocker管理

terraformを用いてインスタンス作成

値の設定

下記の設定を行います。Subnetの設定は将来立てたいインスタンス数に関連してくるので、慎重に決めた方が良いです。小さくしすぎるとインスタンスが将来足りなくなるので適切な設定が必要です。

  • AWSのリージョン
  • Subnetの設定
  • AWSのamiの設定
  • キーファイルの設定

variables.tf

variable "access_key" {}
variable "secret_key" {}

variable "aws_region" {
  description = "The AWS region to create things in."
  default = "ap-northeast-1"
}

variable "aws_region_subnet" {
  description = "The AWS region to create things in."
  default = "ap-northeast-1a"
}

variable "vpc_cidr" {
  description = "CIDR for VPC"
  default     = "10.128.0.0/16"
}

variable "public_subnet_cidr" {
  description = "CIDR for public subnet"
  default     = "10.128.0.0/24"
}

variable "private_subnet_cidr" {
  description = "CIDR for private subnet"
  default     = "10.128.1.0/24"
}

# CentOS:7 (x86_x64)
variable "aws_amis" {
  default = {
      ap-northeast-1 = "ami-1431de75"
  }
}

variable "key_name" {
  description = "Name of the SSH keypair to use in AWS."
  default = {your setting key file }
}

VPCの設定

aws-vpc.tf

注意:terraform.tfvarsでaccess_keysecret_keyの設定が必要です。

下記からやり方を参照下さい。

awsのs3を操作する為のaccess keyとsecret keyを取得する(IAM)

VPCの設定を先ほど設定した値を使用する

  • アクセスキー
  • シークレットキー
  • リージョン
  • vpc_cidr
/* Setup our aws provider */
provider "aws" {
  access_key  = "${var.access_key}"
  secret_key  = "${var.secret_key}"
  region      = "${var.aws_region}"
}

/* Define our vpc */
resource "aws_vpc" "default" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
  tags {
    Name = {your setting tags}
  }
}

publicのサブネット設定

public-subnets.tf

  • デフォルトゲートウェイの設定
  • サブネットの設定
/* Internet gateway for the public subnet */
resource "aws_internet_gateway" "default" {
  vpc_id = "${aws_vpc.default.id}"
}

/* Public subnet */
resource "aws_subnet" "public" {
  vpc_id            = "${aws_vpc.default.id}"
  cidr_block        = "${var.public_subnet_cidr}"
  availability_zone = "${var.aws_region_subnet}"
  map_public_ip_on_launch = true
  depends_on = ["aws_internet_gateway.default"]
  tags {
    Name = "public"
  }
}

/* Routing table for public subnet */
resource "aws_route_table" "public" {
  vpc_id = "${aws_vpc.default.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.default.id}"
  }
}

/* Associate the routing table to public subnet */
resource "aws_route_table_association" "public" {
  subnet_id = "${aws_subnet.public.id}"
  route_table_id = "${aws_route_table.public.id}"
}

セキュリティグループの設定

セキュリティグループの設定
各インスタンスにおけるポートの設定を行います。"ingress"がインスタンスへの入力。"engress"がインスタンスからの出力する際のポートの設定。

  • default
  • nat
  • web
/* Default security group */
resource "aws_security_group" "default" {
  name = "default-research"
  description = "Default security group that allows inbound and outbound traffic from all instance in the VPC"
  vpc_id = "${aws_vpc.default.id}"

  ingress {
    from_port = "0"
    to_port   = "0"
    protocol  = "-1"
    self      = true
  }

  egress {
    from_port = "0"
    to_port   = "0"
    protocol  = "-1"
    self      = true
  }

  tags {
    Name = "research-default-vpc"
  }
}

/* Security group for the nat server */
resource "aws_security_group" "nat" {
  name = "nat-research"
  description = "Default security group that allows inbound and outbound traffic from all instance in the VPC"
  vpc_id = "${aws_vpc.default.id}"

  # ssh
  ingress {
    from_port = "22"
    to_port   = "22"
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port = "1194"
    to_port   = "1194"
    protocol  = "udp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
      from_port = -1
      to_port = -1
      protocol = "icmp"
      cidr_blocks = ["0.0.0.0/0"]
  }

  # http
  egress {
    from_port = "80"
    to_port   = "80"
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # https
  egress {
    from_port = "443"
    to_port   = "443"
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
      from_port = -1
      to_port = -1
      protocol = "icmp"
      cidr_blocks = ["0.0.0.0/0"]
  }

  tags {
    Name = "nat-research-vpc"
  }
}

/* Security group for the web */
resource "aws_security_group" "web" {
  name = "web"
  description = "Default security group that allows inbound and outbound traffic from all instance in the VPC"
  vpc_id = "${aws_vpc.default.id}"

  # http
  ingress {
    from_port = "80"
    to_port   = "80"
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # https
  ingress {
    from_port = "443"
    to_port   = "443"
    protocol  = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags {
    Name = "elasticsearch-crawler-vpc"
  }
}

ssh のキーペアを作成

sshアクセス用の鍵を作成

ssh-keygen -t rsa -C "insecure-deployer" -P '' -f ssh/insecure-deployer

key-pairs.tfを作成

key-pairs.tfでインスタンス先にssh用の鍵を設定

resource "aws_key_pair" "deployer" {
  key_name = "deployer-key"
  public_key = "${file(\"ssh/insecure-deployer.pub\")}"
}

NATサーバーの設定

nat-serverはOpenVPNを使用するためのコンテナを立てるためのサーバーです。ansibleで環境構築を行うためにsecurity_groupsを緩めにしています。構築が終われば、不要なポートは閉じる必要があります。

/* NAT/VPN server */
resource "aws_instance" "nat" {
  ami = "${lookup(var.aws_amis, var.aws_region)}"
  instance_type = "t2.micro"
  subnet_id = "${aws_subnet.public.id}"
  security_groups = ["${aws_security_group.default.id}", "${aws_security_group.nat.id}"]
  key_name = "${var.key_name}"
  associate_public_ip_address = true
  source_dest_check = false
  tags = {
    Name = "nat-staging"
  }
  connection {
    user = "centos"
  }
}

プライベートなサブネットの設定

private-subnets.tf

プライベートなサブネットの設定
"aws_route_table"でnatインスタンスを通ってアクセスするようになっています。

/* Public subnet */
resource "aws_subnet" "private" {
  vpc_id            = "${aws_vpc.default.id}"
  cidr_block        = "${var.private_subnet_cidr}"
  availability_zone = "${var.aws_region_subnet}"
  map_public_ip_on_launch = false
  depends_on = ["aws_instance.nat"]
  tags {
    Name = "private"
  }
}

/* Routing table for public subnet */
resource "aws_route_table" "private" {
  vpc_id = "${aws_vpc.default.id}"
  route {
    cidr_block = "0.0.0.0/0"
    instance_id = "${aws_instance.nat.id}"
  }
}

/* Associate the routing table to public subnet */
resource "aws_route_table_association" "private" {
  subnet_id = "${aws_subnet.private.id}"
  route_table_id = "${aws_route_table.private.id}"
}

webサーバーの設定

サーバーの作成とロードバランサーの作成も行う。
サーバーはプライベートな空間に置く

/* App servers */
resource "aws_instance" "app" {
  count = 2
  ami = "${lookup(var.amis, var.region)}"
  instance_type = "t2.micro"
  subnet_id = "${aws_subnet.private.id}"
  security_groups = ["${aws_security_group.default.id}"]
  key_name = "${aws_key_pair.deployer.key_name}"
  source_dest_check = false
  tags = { 
    Name = "airpair-app-${count.index}"
  }
}

/* Load balancer */
resource "aws_elb" "app" {
  name = "airpair-elb"
  subnets = ["${aws_subnet.public.id}"]
  security_groups = ["${aws_security_group.default.id}", "${aws_security_group.web.id}"]
  listener {
    instance_port = 80
    instance_protocol = "http"
    lb_port = 80
    lb_protocol = "http"
  }
  instances = ["${aws_instance.app.*.id}"]
}

出力の確認

作成したインスタンスのipアドレスの確認方法

output "app.0.ip" {
  value = "${aws_instance.app.0.private_ip}"
}

output "app.1.ip" {
  value = "${aws_instance.app.1.private_ip}"
}

output "nat.ip" {
  value = "${aws_instance.nat.public_ip}"
}

output "elb.hostname" {
  value = "${aws_elb.app.dns_name}"
}

terraformの動作確認

文法のチェック

terraform plan

インスタンスの作成

terraform apply

Ansibleの環境設定

注意:Ubuntu 14.04 LTSのインスタンスでの動作を確認していますが、他のディストリビューションだと動作するか不明です。

NATサーバーの環境設定を行う。

ansibleの構成

- nat_host
- site_nat.yml
- - roles
- - - nat
- - - - tasks
- - - - - main.yml
- - - - - common.yml
- - - - - docker_nat.yml 

秘密鍵は下記を使用

人によって変わります。terarformで使用した公開鍵と対になっている秘密鍵を使用してください

insecure-deployer

NATサーバーのホストの設定

nat_host

[ubuntu]
{NATサーバーのIPアドレス} ansible_ssh_private_key_file={上記の秘密鍵を使用} ansible_ssh_user=ubuntu

設定を行うためのansible

site_nat.yml

---
- name: apply development to all nodes
  hosts: ubuntu
  remote_user: ubuntu
  roles:
  - nat

実際の設定を行う部分

- - roles
- - - nat
- - - - tasks
- - - - - main.yml
- - - - - common.yml
- - - - - docker_nat.yml
- - - vars
- - - - main.yml

nat/tasks/main.yml

共通の設定とOpenVPNを設定するためのDockerの設定

---
- include: common.yml
- include: docker_nat.yml

common.yml

dockerに必要な共通の設定を行う。

---
- name: apt-get updates a server
  apt: update_cache=yes
  sudo: yes
  tags: initial_setup

- name: apt-get upgrade a server
  apt: upgrade=full
  sudo: yes
  tags: initial_setup

- name: apt-get install basic pkg
  apt: pkg={{ item }} state=installed
  sudo: yes
  with_items:
  - git
  - gcc
  - build-essential
  - gfortran
  - e2fslibs-dev
  - openjdk-7-jre-headless
  - dstat
  - sysstat
  tags: initial_setup

docker_nat.yml

DockerのOpenVPNの設定

注意:再起動の部分で繋がらなくて落ちるかもしれません。もし落ちた場合は再起動以降から実行するようにしてください。

---
- name: apt-get updates a server
  apt: update_cache=yes
  sudo: yes
  tags: initial_setup

- name: apt-get install basic pkg
  apt: pkg={{ item }} state=installed
  sudo: yes
  with_items:
  - apt-transport-https
  - ca-certificates

- name: Add Docker repository key
  shell: apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
  sudo: yes
  tags: docker

- name: make lsit
  shell: touch /etc/apt/sources.list.d/docker.list && echo deb https://apt.dockerproject.org/repo ubuntu-trusty main >> /etc/apt/sources.list.d/docker.list
  sudo: yes
  tags: docker

- name: apt-get updates a server restart
  apt: update_cache=yes
  sudo: yes
  tags: initial_setup

- name: purge docker
  shell: apt-get purge lxc-docker
  sudo: yes
  tags: docker

- name: cache docker
  shell: apt-cache policy docker-engine
  sudo: yes
  tags: initial_setup

- name: apt-get install linux extra image pkg
  apt: pkg=linux-image-extra-3.13.0-79-generic state=installed
  sudo: yes
  tags: initial_setup

- name: apt-get updates a server
  apt: update_cache=yes
  sudo: yes
  tags: initial_setup

- name: apt-get install linux image generic pkg
  apt: pkg=linux-image-generic-lts-trusty state=installed
  sudo: yes
  tags: initial_setup

- name: Restart the server
  shell: reboot now
  sudo: yes

- name: Wait until the virtual machine stop ssh port stop responding
  local_action: wait_for host={{ inventory_hostname }} port=22 state=stopped
  sudo: false

- name: Wait for server to come up
  local_action: wait_for host={{ inventory_hostname }} port=22 delay=30
  sudo: false

- name: apt-get updates a server
  apt: update_cache=yes
  sudo: yes
  tags: initial_setup

- name: apt-get install docker-engine
  shell: apt-get install --force-yes -y docker-engine
  sudo: yes
  tags: docker

- name: usermod -aG docker ubuntu
  shell: usermod -aG docker ubuntu
  sudo: yes
  tags: docker

- name: nat setting
  shell: iptables -t nat -A POSTROUTING -j MASQUERADE
  sudo: yes
  tags: nat

- name: nat setting2
  shell: echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/forwarding > /dev/null
  sudo: yes
  tags: nat

- name: nat setting3
  shell: mkdir -p /etc/openvpn && docker run --name ovpn-data -v /etc/openvpn busybox
  sudo: yes
  tags: nat

- name: nat setting4
  shell: docker run --volumes-from ovpn-data --rm gosuri/openvpn ovpn_genconfig -p {{ vpc_cidr }} -u udp://{{ public_ip }}
  sudo: yes
  tags: nat
ansible-playbook -i ansible_host site.yml

ansible_hostでご自身で作成したインスタンスのipアドレスの設定をしてください。

nat/tasks/main.yml

ここで再起動用のためにインスタンスのipアドレスを指定下さい。

---
inventory_hostname: {your instance ip}

dockerの起動からVPNの開通まで

OpenVPN用のDockerコンテナを起動し、VPN接続まで行うステップです。

dockerのOpenVPNコンテナの初期設定

ここで設定した秘密鍵を使用
人によって変わります。terarformで使用した公開鍵と対になっている秘密鍵を使用してください

insecure-deployer
ssh -t -i {秘密鍵} \
"ubuntu@{IPアドレス}" -p {ポート} \
sudo docker run --volumes-from ovpn-data --rm -it gosuri/openvpn ovpn_initpki

dockerのOpenVPNコンテナ起動

ssh -t -i {秘密鍵} \
"centos@{IPアドレス}" -p {ポート} \
sudo docker run --volumes-from ovpn-data -d -p 1194:1194/udp --cap-add=NET_ADMIN gosuri/openvpn

クライアント側にdockerの設定を反映

ssh -t -i {秘密鍵} \
"ubuntu@{IPアドレス}" -p {ポート} \
sudo docker run --volumes-from ovpn-data --rm -it gosuri/openvpn easyrsa build-client-full $USER nopass

Tunnelblickに設定するためのファイル作成

*注意点:作成されたファイルのIPアドレスが適切でない場合があります。Dockerが動作しているコンテナのIPアドレスを設定しましょう。

ssh -t -i {秘密鍵} \
"ubuntu@{IPアドレス}" -p {ポート} \
sudo docker run --volumes-from ovpn-data --rm gosuri/openvpn ovpn_getclient $USER > "test.ovpn"

VPNの接続

Screen Shot 2016-06-14 at 8.31.48 PM.png

TunnelBlickの設定を行いましょう。

作成したtest.ovpnをインストールしたTunnelBlickにドラッグ&ドロップして設定を行いましょう。
パスワードの入力が求められるのでパスワードの入力をすれば設定可能です。

sshで動作確認

ssh -i 秘密鍵 ubuntu@プライベートipアドレス

上記で接続可能です。

後片付け

terraformのフォルダに移動して今回使用したインスタンスは破棄しおきましょう。

インスタンス破棄

terraform destroy

コード

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12