实习中遇到个问题,现有的openvpn配置很乱

需要重新梳理客户端和服务端的对应关系。于是写了个Ansible脚本来扫描客户端配置文件

提取出所有Client的配置文件,并生成一个对应关系报告。

已知现在机器上面所有的OpenVPN客户端配置文件都在/etc/openvpn/client/目录下。

ansible-playbook的脚本文件如下(因为我这用的服务器的ansible比较老,所以格式可能不太一样):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
---
- name: 第 1 步 - 从 OpenVPN 客户端配置中发现公网 IP 及其文件名
  hosts: all
  become: yes
  gather_facts: no
  vars:
    # 定义要扫描的 OpenVPN 客户端配置目录
    openvpn_client_dir: /etc/openvpn/client

  tasks:
    - name: "扫描 {{ openvpn_client_dir }} 目录下的配置文件 (递归搜索并关联文件名)"
      shell: >
        grep -rHE '^remote\s+' {{ openvpn_client_dir }} 2>/dev/null |
        grep -vE ':remote\s+(192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|127\.|localhost)' |
        sed -E 's#^.*/([^:]+):remote[[:space:]]+([^ ]+).*#\2--->\1#' |
        sort -u || true
      # 这个 shell 命令执行以下操作:
      # 1. `grep -rHE '^remote\s+'`: 递归搜索并打印“文件名:匹配行”。
      #    - `-H`: 强制打印文件名。
      # 2. `grep -vE ':remote\s+(私网IP正则)'`: 过滤掉包含私网IP的行。
      # 3. `sed -E 's#...#...#'`: 使用正则表达式重新格式化输出。
      #    - 它会将 "路径/文件名.ovpn:remote 1.2.3.4 ..." 格式化为 "1.2.3.4--->文件名.ovpn"
      # 4. `sort -u`: 对最终结果进行排序和去重。
      # 5. `|| true`: 确保在没有找到文件或匹配项时,任务不会失败。
      register: public_ips_found
      changed_when: false

    - name: "为找到的 'IP--->文件名' 设置变量"
      set_fact:
        openvpn_public_ips: "{{ public_ips_found.stdout_lines }}"

- name: 第 2 步 - 生成汇总报告
  hosts: localhost
  connection: local
  gather_facts: no
  become: no

  tasks:
    - name: "汇总所有主机上发现的'IP--->文件名'映射"
      set_fact:
        all_public_ips: "{{ all_public_ips | default([]) + hostvars[item]['openvpn_public_ips'] }}"
      loop: "{{ groups['all'] }}"
      when: hostvars[item]['openvpn_public_ips'] is defined and hostvars[item]['openvpn_public_ips'] | length > 0

    - name: "将唯一的'IP--->文件名'列表写入本地文件"
      copy:
        content: "{{ all_public_ips | unique | join('\n') }}\n"
        dest: "./result_public_ip_mapping.txt"
      when: all_public_ips is defined and all_public_ips | length > 0

把这个ansible脚本保存为 scan_openvpn_ips.yml

把需要扫描的客户端主机名写入一个文件 vpnclient_list.ini,这里我不知道Client的登录端口是22还是8822,所以都写上了。

类似这样:

1
2
3
[shimokitazawa]
1.2.3.4 ansible_port=22
1.2.3.4 ansible_port=8822

执行

1
ansible-playbook -i vpnclient_list.ini count_vpn_client.yml 2>&1 | tee playbook.log

最终输出会到result_public_ip_mapping.txt里面

效果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|># cat result_public_ip_mapping.txt 
114.514.19.81--->xiuxiu.ovpn
114.514.19.81--->shimokitazawa.ovpn
114.514.19.81--->sample.ovpn
191.981.0.81--->tokyo.ovpn
810.191.98.10--->osaka.ovpn
233.333.33.33--->nagoya.ovpn
666.666.66.66--->kyoto.ovpn
404.404.40.44--->sapporo.ovpn
520.131.41.41--->fukuoka.ovpn
250.250.25.25--->sendai.ovpn
123.456.78.90--->hakata.ovpn
999.888.77.66--->shibuya.ovpn
314.159.26.53--->akihabara.ovpn
810.191.98.10--->ikebukuro.ovpn
114.514.19.10--->kawasaki.ovpn
114.514.19.10--->yokohama.ovpn
191.981.0.10--->chiba.ovpn
233.666.66.66--->kobe.ovpn
191.981.0.81--->saitama.ovpn
404.404.40.44--->ueno.ovpn
810.191.98.10--->shinagawa.ovpn
114.514.19.81--->shimokitazawa.ovpn

自此,所有的OpenVPN客户端配置文件的公网IP和对应的文件名都被提取出来了。

参考资料:

https://ansible-tran.readthedocs.io/en/latest/docs/playbooks_intro.html#playbook-basics