IaCLinuxNetworkPython

AnsibleでOpenVPNのインストールをコード化する

IaC

以前に紹介した以下の記事で、AWS上のAmazonLinux2にOpenVPNサーバを構築しました。

AWS上のEC2でOpenVPNサーバを構築する 
https://syachiku.net/ec2openvpn-1/

ただし、OpenVPNサーバを構築するには証明局や証明書の作成などのかなり多くの手順が必要となり複雑です。

そこで、構成管理ツールであるAnsibleを利用してOpenVPNの構築をコード化(IaC)してみました。

ansible-playbookのコマンド一発で簡単にOpenVPNサーバが構築できるようにします。

1. 前提

  • EC2上に素のAmazonLinux2のインスタンスは用意されている
  • 証明局とサーバ証明書、クライアント証明書は新規で作成する
  • 細かいansibleの利用方法については解説しません。

2. 構築処理の流れ

基本的には以下の記事と同じ手順で構築しています。

AWS上のEC2でOpenVPNサーバを構築する 
https://syachiku.net/ec2openvpn-1/

3. 作成したansible playbookについて

作成したansible playbookについて記載した後に、実際の構築手順について説明したいと思います。

3.1. ディレクトリ構成

/etc/ansible/以下のディレクトリは以下のようにしました。
localhostに対して実行するのでhostsファイルは不要です。 ベストプラクティスに沿って構築しているつもりです。

/etc/ansible/
├── ansible.cfg
├── hosts
├── roles
│   └── vpn
│       ├── files
│       │   ├── client.ovpn
│       │   └── server.conf
│       ├── handlers
│       │   └── main.yml
│       └── tasks
│           └── main.yml
├── site.yml
└── vars
    └── variables.yml

3.2. site.yml

こんな感じです。localhostに対してvpnのroleを実施しています。

- hosts: localhost
  become: yes
  become_user: root
  vars_files:
    - ./vars/variables.yml
  roles:
    - vpn

3.3. vars/variables.yml

変数を格納していますが、今回はたったこれだけです。今後の拡張を考えて一応変数にしました。

openvpn_easyrsa_path: /usr/share/easy-rsa/3

3.4. roles/vpn/tasks/main.yml

ここがタスクのメインですamazon-linux-extrasを利用する方法がパッと調べてもなかったのでshellで実行しています。

- name: enable amazon-linux-extras epel
  shell: "amazon-linux-extras install -y epel"

- name: install openvpn
  yum:
    name: openvpn
    enablerepo: amzn2extra-epel
    state: present

- name: install openvpn and easy-rsa
  yum:
    name: "{{ item }}"
    enablerepo: amzn2extra-epel
    state: present
    update_cache: yes
  with_items: [easy-rsa, openvpn]

- name: ensure /etc/openvpn/easy-rsa exists
  ansible.builtin.file:
    path: /etc/openvpn/easy-rsa
    state: directory
    mode: "0755"

- name: easyrsa init-pki
  ansible.builtin.command:
    cmd: "/usr/share/easy-rsa/3/easyrsa init-pki"
    chdir: /etc/openvpn/easy-rsa
    creates: /etc/openvpn/easy-rsa/pki

- name: easyrsa build-ca
  ansible.builtin.command:
    cmd: "/usr/share/easy-rsa/3/easyrsa build-ca nopass"
    chdir: /etc/openvpn/easy-rsa
    creates: /etc/openvpn/easy-rsa/pki/ca.crt
  environment:
    EASYRSA_BATCH: "yes"

- name: easyrsa gen-dh
  ansible.builtin.command:
    cmd: "/usr/share/easy-rsa/3/easyrsa gen-dh"
    chdir: /etc/openvpn/easy-rsa
    creates: /etc/openvpn/easy-rsa/pki/dh.pem

- name: easyrsa build-server-full server nopass
  ansible.builtin.command:
    cmd: "/usr/share/easy-rsa/3/easyrsa build-server-full server nopass"
    chdir: /etc/openvpn/easy-rsa
    creates: /etc/openvpn/easy-rsa/pki/issued/server.crt

- name: easyrsa build-client-full client nopass
  ansible.builtin.command:
    cmd: "{{ openvpn_easyrsa_path }}/easyrsa build-client-full client nopass"
    chdir: /etc/openvpn/easy-rsa
    creates: /etc/openvpn/easy-rsa/pki/issued/client.crt

- name: openvpn --genkey --secret /etc/openvpn/easy-rsa/pki/ta.key
  ansible.builtin.command:
    cmd: openvpn --genkey --secret /etc/openvpn/easy-rsa/pki/ta.key
    creates: /etc/openvpn/easy-rsa/pki/ta.key

- name: copy files to /etc/openvpn/server
  ansible.builtin.copy:
    src: /etc/openvpn/easy-rsa/pki/{{ item }}
    dest: /etc/openvpn/{{ item | basename }}
    mode: "0640"
    remote_src: yes
  loop:
    - ca.crt
    - dh.pem
    - ta.key
    - issued/server.crt
    - private/ca.key
    - private/server.key

- name: copy files for client to /home/ec2-user
  ansible.builtin.copy:
    src: /etc/openvpn/easy-rsa/pki/{{ item }}
    dest: /home/ec2-user/{{ item | basename }}
    mode: "0666"
    remote_src: yes
  loop:
    - ca.crt
    - ta.key
    - issued/client.crt
    - private/client.key

- name: copy openvpn config file
  copy: 
    src: server.conf
    dest: /etc/openvpn/server.conf
    owner: root
    group: root
    mode: 0644
  notify: vpn restart

- name: copy openvpn client ovpn file
  copy: 
    src: client.ovpn
    dest: /home/ec2-user/client.ovpn
    owner: root
    group: root
    mode: 0644

- name: enable ipv4.ip_forward
  sysctl:
    name: net.ipv4.ip_forward
    value: '1'
    state: present
    sysctl_set: yes
    reload: true

- name: start and enable openvpn
  ansible.builtin.service:
    name: "openvpn@server"
    state: started
    enabled: yes

3.5. roles/vpn/handlers/main.yml

OpenVPNサーバの再起動コマンドです。

- name: vpn restart
  shell: systemctl restart openvpn@server

3.6. roles/vpn/files

  • server.conf
    • push routeやDNSなどの設定は適宜変更してください。
    • 443ポートでVPN接続するようにしています。
port 443
proto tcp
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh dh.pem
server 192.168.10.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 10.1.0.0 255.255.0.0"
push "dhcp-option DNS 10.1.100.4"
push "dhcp-option DNS 10.1.200.144"
keepalive 10 120
tls-auth ta.key 0 # This file is secret
cipher AES-256-CBC
persist-key
persist-tun
status openvpn-status.log
log         openvpn.log
log-append  openvpn.log
verb 3
explicit-exit-notify 0
  • client.ovpn
    • remoteのxx.xx.xx.xxは後でVPNサーバのPublicIPに手動で変更します
client
dev tun
proto tcp
remote xx.xx.xx.xx 443
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
remote-cert-tls server
tls-auth ta.key 1
cipher AES-256-CBC
verb 3

4. 結果としてできるもの

  • AmazonLinux2のOpenVPNサーバがインストールされ、証明書関連もセットアップがされて、OpenVPNサービスが起動します。
  • クライアント(PC)で利用する証明書と設定ファイル(ひな形)が作成されて/home/ec2-user/に配置されます

5. OpenVPNの構築の実施

5.1. ansibleのインストール

ansibleのインストール方法については以下を参考にして下さい。簡単です。

EC2インスタンスとして構築したAmazonLinux2へAnsibleをインストール(yum) 
https://syachiku.net/amazonlinux2-ansible-install/

5.2. ansible-playbookの実行

ansible-playbookを実行してOpenサーバを構築します。 全部で5分くらいかかります。

# ansible-playbook /etc/ansible/site.yml

PLAY [localhost] ***************************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]
.
(略)
.
RUNNING HANDLER [vpn restart] **************************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=18   changed=17   unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

5.3. AWS側設定

AWSインスタンス側で設定変更をします。

5.4. OpenVPNクライアント設定

/home/ec2-user/に配置されている証明書と設定ファイルをPC側にダウンロードします。

サーバ側のPubluc IPアドレスを確認して、設定ファイル(client.ovpn)の接続先を書き換えます。

OpenVPNクライアントのインストールや設定を行います。
 https://syachiku.net/ec2openvpn-1/#toc15

5.5. 接続確認

最後にVPNサーバに接続できる事を確認します。

6. まとめ

Ansibleを利用してAmazonLinux2にOpenVPN環境をかなり簡単に構築することができるようになりました。

私は普段はChefを利用していて、今回はじめて本格的にAnsibleを利用してみましたが、chefよりも使いやすいかもしれませんね。

次はせっかくAWSで構築していますので、最後の仕上げとしてCloudFormationと今回のAnsible Playbookを組み合わせてEC2の作成からサーバ構築までを自動化してみたいと思います。

ansibleの学習には以下の書籍を利用しています。かなり分かりやすくてオススメです。

追記

以下の記事で最終的にCloudFormationとAnsibleを組み合わせてみました。

CloudFormationとAnsibleでEC2インスタンス構築時にOpenVPN構築してみた。
https://syachiku.net/cloudformation-ansible-userdata/

AWSを効率的に学習する方法

私が効率的にAWSを学習するために実施した方法は以下の通りです。
 ①最初に書籍(ハンズオンができる)を購入、座学でAWSの基礎を学習
 ②AWS資格試験を取得ための学習

※私の場合は①と②を合わせて2か月でソリューションアーキテクトを取得できました。

①AWS基礎学習

最初に購入した書籍は「Amazon Web Services 基礎からのネットワーク&サーバー構築」です。

Amazon Web Services 基礎からのネットワーク&サーバー構築

この本では、AWSの基本サービスを利用したハンズオンを通じて、AWSの基礎を学習することができます。

また、タイトル通りAWSのネットワークやインフラに関しても網羅しているため、もともとインフラ系の技術者ではない人たちにとっても分かりやすい内容だと思います。

とりあえずAWS上にサーバーを設定して開発を行うための準備までするには最良の一冊です。

Amazon Web Services 基礎からのネットワーク&サーバー構築

②AWS資格取得

AWSの基礎をある程度学習することができたら、次はAWS資格を取得しましょう。まずはAWSソリューションアーキテクトを目指しましょう。

資格勉強のための問題集をひたすら解きながら、AWSの知識を積み重ねて習得していきましょう!

苦行ではありますがこの問題集を3周ほどすればAWS用語や構成に関しても習得できているはずです。

AWS認定ソリューションアーキテクト-アソシエイト問題集

今回は以上となります。

コメント