diff --git a/.travis.yml b/.travis.yml
index 76d8bb2..904dbdb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -45,4 +45,7 @@ install:
script:
- ansible-playbook deploy.yml --syntax-check
- - ansible-playbook deploy.yml -t local,vpn,dns,ssh_tunneling,security -e "server_ip=$LXC_IP server_user=root IP_subject_alt_name=$LXC_IP local_dns=Y"
+ - ansible-playbook deploy.yml -t local,vpn,dns,ssh_tunneling,security,tests -e "server_ip=$LXC_IP server_user=root IP_subject_alt_name=$LXC_IP local_dns=Y"
+
+after_script:
+ - ./tests/update-users.sh
\ No newline at end of file
diff --git a/algo b/algo
index 26fbbd2..d001a6e 100755
--- a/algo
+++ b/algo
@@ -50,6 +50,12 @@ Do you want the VPN to support Windows 10 clients? (requires RSA certificates an
Win10_Enabled=${Win10_Enabled:-n}
if [[ "$Win10_Enabled" =~ ^(y|Y)$ ]]; then EXTRA_VARS+=" Win10_Enabled=Y"; fi
+read -p "
+Do you want to store the CA key? (required for update-users script, but less secure)
+[y/N]: " -r Store_CAKEY
+Store_CAKEY=${Store_CAKEY:-N}
+if [[ "$Store_CAKEY" =~ ^(n|N)$ ]]; then EXTRA_VARS+=" Store_CAKEY=N"; fi
+
}
deploy () {
@@ -332,7 +338,31 @@ Enter the number of your desired provider
}
user_management () {
- ansible-playbook users.yml
+
+ read -p "
+Enter IP address of your server: (use localhost for local installation)
+: " -r server_ip
+
+ read -p "
+What user should we use to login on the server? (ignore if you're deploying to localhost)
+[root]: " -r server_user
+ server_user=${server_user:-root}
+
+read -p "
+Do you want each user to have their own account for SSH tunneling?
+[y/N]: " -r ssh_tunneling_enabled
+ssh_tunneling_enabled=${ssh_tunneling_enabled:-n}
+
+ read -p "
+Enter the public IP address of your server: (IMPORTANT! This IP is used to verify the certificate)
+: " -r IP_subject
+
+ read -p "
+Enter the password for the private CA key:
+[pasted values will not be displayed]
+: " -rs easyrsa_CA_password
+
+ansible-playbook users.yml -e "server_ip=$server_ip server_user=$server_user ssh_tunneling_enabled=$ssh_tunneling_enabled IP_subject=$IP_subject easyrsa_CA_password=$easyrsa_CA_password"
}
case "$1" in
diff --git a/deploy.yml b/deploy.yml
index 7b7e9ef..94a6c3d 100644
--- a/deploy.yml
+++ b/deploy.yml
@@ -63,3 +63,18 @@
- debug: msg="{{ additional_information.split('\n') }}"
tags: cloud
+
+ - name: Save the CA key password
+ local_action: >
+ shell echo "{{ easyrsa_CA_password }}" > /tmp/ca_password
+ become: no
+ tags: tests
+
+ - name: Delete the CA key
+ local_action:
+ module: file
+ path: "configs/{{ IP_subject_alt_name }}/pki/private/cakey.pem"
+ state: absent
+ become: no
+ tags: always
+ when: Store_CAKEY is defined and Store_CAKEY == "N"
diff --git a/roles/ssh_tunneling/tasks/main.yml b/roles/ssh_tunneling/tasks/main.yml
index b279b02..ba0baf2 100644
--- a/roles/ssh_tunneling/tasks/main.yml
+++ b/roles/ssh_tunneling/tasks/main.yml
@@ -57,13 +57,13 @@
template: src=known_hosts.j2 dest=/root/.ssh/{{ IP_subject_alt_name }}_known_hosts
- name: Fetch users SSH private keys
- fetch: src='/var/jail/{{ item }}/.ssh/id_rsa' dest=configs/{{ IP_subject_alt_name }}_{{ item }}.ssh.pem flat=yes
+ fetch: src='/var/jail/{{ item }}/.ssh/id_rsa' dest=configs/{{ IP_subject_alt_name }}/{{ IP_subject_alt_name }}_{{ item }}.ssh.pem flat=yes
with_items: "{{ users }}"
- name: Change mode for SSH private keys
- local_action: file path=configs/{{ IP_subject_alt_name }}_{{ item }}.ssh.pem mode=0600
+ local_action: file path=configs/{{ IP_subject_alt_name }}/{{ IP_subject_alt_name }}_{{ item }}.ssh.pem mode=0600
with_items: "{{ users }}"
become: false
- name: Fetch the known_hosts file
- fetch: src='/root/.ssh/{{ IP_subject_alt_name }}_known_hosts' dest=configs/{{ IP_subject_alt_name }}_known_hosts flat=yes
+ fetch: src='/root/.ssh/{{ IP_subject_alt_name }}_known_hosts' dest=configs/{{ IP_subject_alt_name }}/{{ IP_subject_alt_name }}_known_hosts flat=yes
diff --git a/roles/vpn/tasks/main.yml b/roles/vpn/tasks/main.yml
index 1770ac5..16b0bf1 100644
--- a/roles/vpn/tasks/main.yml
+++ b/roles/vpn/tasks/main.yml
@@ -9,6 +9,12 @@
- set_fact:
easyrsa_p12_export_password: "{{ (ansible_date_time.iso8601_basic|sha1|to_uuid).split('-')[0] }}"
easyrsa_CA_password: "{{ CA_password.stdout }}"
+ IP_subject_alt_name: "{{ IP_subject_alt_name }}"
+
+- name: Change the algorithm to RSA
+ set_fact:
+ algo_params: "rsa:2048"
+ when: Win10_Enabled is defined and Win10_Enabled == "Y"
- name: Install StrongSwan
apt: name=strongswan state=latest update_cache=yes
@@ -97,153 +103,206 @@
when: item in strongswan_enabled_plugins
with_items: "{{ strongswan_plugins.stdout_lines }}"
-- name: Fetch easy-rsa-ipsec from git
- git:
- repo: git://github.com/ValdikSS/easy-rsa-ipsec.git
- version: ipsec-with-patches
- dest: "{{ easyrsa_dir }}"
-
-- name: Setup the vars file from our template
- template: src=easy-rsa.vars.j2 dest={{ easyrsa_dir }}/easyrsa3/vars
-
- name: Ensure the pki directory is not exist
- file: dest={{ easyrsa_dir }}/easyrsa3/pki state=absent
+ local_action:
+ module: file
+ dest: configs/{{ IP_subject_alt_name }}/pki
+ state: absent
+ become: no
when: easyrsa_reinit_existent == True
-- name: Build the pki enviroments
- shell: >
- ./easyrsa init-pki &&
- touch '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized'
- args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
- creates: '{{ easyrsa_dir }}/easyrsa3/pki/pki_initialized'
+- name: Ensure the pki directories are exist
+ local_action:
+ module: file
+ dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}"
+ state: directory
+ recurse: yes
+ become: no
+ with_items:
+ - ecparams
+ - certs
+ - crl
+ - newcerts
+ - private
+ - reqs
+
+- name: Ensure the files are exist
+ local_action:
+ module: file
+ dest: "configs/{{ IP_subject_alt_name }}/pki/{{ item }}"
+ state: touch
+ become: no
+ with_items:
+ - ".rnd"
+ - "private/.rnd"
+ - "index.txt"
+ - "index.txt.attr"
+ - "serial"
+
+- name: Generate the openssl server configs
+ local_action:
+ module: template
+ src: openssl.cnf.j2
+ dest: "configs/{{ IP_subject_alt_name }}/pki/openssl.cnf"
+ become: no
- name: Build the CA pair
- shell: >
- ./easyrsa --batch build-ca -- -passout pass:"{{ easyrsa_CA_password }}" &&
- touch {{ easyrsa_dir }}/easyrsa3/pki/ca_initialized
+ local_action: >
+ shell openssl ecparam -name prime256v1 -out ecparams/prime256v1.pem &&
+ openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/cakey.pem -out cacert.pem -x509 -days 3650 -batch -passout pass:"{{ easyrsa_CA_password }}" &&
+ touch {{ IP_subject_alt_name }}_ca_generated
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
- creates: '{{ easyrsa_dir }}/easyrsa3/pki/ca_initialized'
- notify:
- - restart strongswan
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: "{{ IP_subject_alt_name }}_ca_generated"
+ environment:
+ subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}"
+
+- name: Copy the CA certificate
+ local_action:
+ module: copy
+ src: "configs/{{ IP_subject_alt_name }}/pki/cacert.pem"
+ dest: "configs/{{ IP_subject_alt_name }}/cacert.pem"
+ mode: 0600
+ become: no
+
+- name: Generate the serial number
+ local_action: >
+ shell echo 01 > serial &&
+ touch serial_generated
+ become: no
+ args:
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: serial_generated
- name: Build the server pair
- shell: >
- ./easyrsa gen-req {{ IP_subject_alt_name }} batch nopass -- -subj "/CN={{ IP_subject_alt_name }}" &&
- ./easyrsa --subject-alt-name='DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}' sign-req server {{ IP_subject_alt_name }} -- -passin pass:"{{ easyrsa_CA_password }}" &&
- touch '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized'
+ local_action: >
+ shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ IP_subject_alt_name }}.key -out reqs/{{ IP_subject_alt_name }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" -batch &&
+ openssl ca -utf8 -in reqs/{{ IP_subject_alt_name }}.req -out certs/{{ IP_subject_alt_name }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ IP_subject_alt_name }}" &&
+ touch certs/{{ IP_subject_alt_name }}_crt_generated
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
- creates: '{{ easyrsa_dir }}/easyrsa3/pki/server_initialized'
- notify:
- - restart strongswan
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: certs/{{ IP_subject_alt_name }}_crt_generated
+ environment:
+ subjectAltName: "DNS:{{ IP_subject_alt_name }},IP:{{ IP_subject_alt_name }}"
- name: Build the client's pair
- shell: >
- ./easyrsa gen-req {{ item }} nopass -- -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" &&
- ./easyrsa --subject-alt-name='DNS:{{ item }}' sign-req client {{ item }} nopass -- -passin pass:"{{ easyrsa_CA_password }}" &&
- touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized'
+ local_action: >
+ shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ item }}.key -out reqs/{{ item }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" -batch &&
+ openssl ca -utf8 -in reqs/{{ item }}.req -out certs/{{ item }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" &&
+ touch certs/{{ item }}_crt_generated
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
- creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: certs/{{ item }}_crt_generated
+ environment:
+ subjectAltName: "DNS:{{ item }}"
with_items: "{{ users }}"
- name: Build the client's p12
- shell: >
- openssl pkcs12 -in {{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt -inkey {{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.key -export -name {{ item }} -out /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 -certfile {{ easyrsa_dir }}/easyrsa3//pki/ca.crt -passout pass:"{{ easyrsa_p12_export_password }}"
+ local_action: >
+ shell openssl pkcs12 -in certs/{{ item }}.crt -inkey private/{{ item }}.key -export -name {{ item }} -out private/{{ item }}.p12 -certfile cacert.pem -passout pass:"{{ easyrsa_p12_export_password }}"
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
with_items: "{{ users }}"
+- name: Copy the p12 certificates
+ local_action:
+ module: copy
+ src: "configs/{{ IP_subject_alt_name }}/pki/private/{{ item }}.p12"
+ dest: "configs/{{ IP_subject_alt_name }}/{{ item }}.p12"
+ mode: 0600
+ become: no
+ with_items:
+ - "{{ users }}"
+
- name: Copy the CA cert to the strongswan directory
- copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/ca.crt' dest=/etc/ipsec.d/cacerts/ca.crt owner=strongswan group=root mode=0600
+ copy: src='configs/{{ IP_subject_alt_name }}/pki/cacert.pem' dest=/etc/ipsec.d/cacerts/ca.crt owner=strongswan group=root mode=0600
notify:
- restart strongswan
- name: Copy the server cert to the strongswan directory
- copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/issued/{{ IP_subject_alt_name }}.crt' dest=/etc/ipsec.d/certs/{{ IP_subject_alt_name }}.crt owner=strongswan group=root mode=0600
+ copy: src='configs/{{ IP_subject_alt_name }}/pki/certs/{{ IP_subject_alt_name }}.crt' dest=/etc/ipsec.d/certs/{{ IP_subject_alt_name }}.crt owner=strongswan group=root mode=0600
notify:
- restart strongswan
- name: Copy the server key to the strongswan directory
- copy: remote_src=True src='{{ easyrsa_dir }}/easyrsa3/pki/private/{{ IP_subject_alt_name }}.key' dest=/etc/ipsec.d/private/{{ IP_subject_alt_name }}.key owner=strongswan group=root mode=0600
+ copy: src='configs/{{ IP_subject_alt_name }}/pki/private/{{ IP_subject_alt_name }}.key' dest=/etc/ipsec.d/private/{{ IP_subject_alt_name }}.key owner=strongswan group=root mode=0600
notify:
- restart strongswan
- name: Register p12 PayloadContent
- shell: >
- cat /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 | base64
+ local_action: >
+ shell cat private/{{ item }}.p12 | base64
register: PayloadContent
+ become: no
+ args:
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
with_items: "{{ users }}"
-- name: Register CA PayloadContent
- shell: >
- cat /{{ easyrsa_dir }}/easyrsa3/pki/ca.crt | base64
- register: PayloadContentCA
-
- name: Set facts for mobileconfigs
set_fact:
proxy_enabled: false
+ PayloadContentCA: "{{ lookup('file' , 'configs/{{ IP_subject_alt_name }}/pki/cacert.pem')|b64encode }}"
- name: Build the mobileconfigs
- template: src=mobileconfig.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item.0 }}.mobileconfig mode=0600
+ local_action:
+ module: template
+ src: mobileconfig.j2
+ dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.mobileconfig
+ mode: 0600
+ become: no
with_together:
- "{{ users }}"
- "{{ PayloadContent.results }}"
no_log: True
- name: Build the client ipsec config file
- template: src=client_ipsec.conf.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/ipsec_{{ item }}.conf mode=0600
+ local_action:
+ module: template
+ src: client_ipsec.conf.j2
+ dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.conf
+ mode: 0600
+ become: no
with_items:
- "{{ users }}"
- name: Build the client ipsec secret file
- template: src=client_ipsec.secrets.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/ipsec_{{ item }}.secrets mode=0600
+ local_action:
+ module: template
+ src: client_ipsec.secrets.j2
+ dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.secrets
+ mode: 0600
+ become: no
with_items:
- "{{ users }}"
-- name: Fetch users P12
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 dest=configs/{{ IP_subject_alt_name }}_{{ item }}.p12 flat=yes
- with_items: "{{ users }}"
-
-- name: Fetch users mobileconfig
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.mobileconfig dest=configs/{{ IP_subject_alt_name }}_{{ item }}.mobileconfig flat=yes
- with_items: "{{ users }}"
-
-- name: Fetch users certificates
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt dest=configs/{{ IP_subject_alt_name }}_{{ item }}.crt flat=yes
- with_items: "{{ users }}"
-
-- name: Fetch users keys
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.key dest=configs/{{ IP_subject_alt_name }}_{{ item }}.key flat=yes
- with_items: "{{ users }}"
-
-- name: Fetch users ipsec configs
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/ipsec_{{ item }}.conf dest=configs/{{ IP_subject_alt_name }}_{{ item }}_ipsec.conf flat=yes
- with_items: "{{ users }}"
-
-- name: Fetch users ipsec secrets
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/ipsec_{{ item }}.secrets dest=configs/{{ IP_subject_alt_name }}_{{ item }}_ipsec.secrets flat=yes
- with_items: "{{ users }}"
-
- name: Build the windows client powershell script
- template: src=client_windows.ps1.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/windows_{{ item }}.ps1 mode=0600
+ local_action:
+ module: template
+ src: client_windows.ps1.j2
+ dest: configs/{{ IP_subject_alt_name }}/windows_{{ item }}.ps1
+ mode: 0600
+ become: no
when: Win10_Enabled is defined and Win10_Enabled == "Y"
with_items: "{{ users }}"
-- name: Fetch users windows scripts
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/windows_{{ item }}.ps1 dest=configs/{{ IP_subject_alt_name }}_{{ item }}_windows.ps1 flat=yes
- when: Win10_Enabled is defined and Win10_Enabled == "Y"
- with_items: "{{ users }}"
-
-- name: Restrict permissions
+- name: Restrict permissions for the remote private directories
file: path="{{ item }}" state=directory mode=0700 owner=strongswan group=root
with_items:
- /etc/ipsec.d/private
-- name: Fetch server CA certificate
- fetch: src=/{{ easyrsa_dir }}/easyrsa3/pki/ca.crt dest=configs/{{ IP_subject_alt_name }}_ca.crt flat=yes
+- name: Restrict permissions for the local private directories
+ local_action:
+ module: file
+ path: "{{ item }}"
+ state: directory
+ mode: 0700
+ become: no
+ with_items:
+ - configs/{{ IP_subject_alt_name }}
- include: iptables.yml
tags: iptables
diff --git a/roles/vpn/templates/easy-rsa.vars.j2 b/roles/vpn/templates/easy-rsa.vars.j2
deleted file mode 100644
index 2805b3b..0000000
--- a/roles/vpn/templates/easy-rsa.vars.j2
+++ /dev/null
@@ -1,202 +0,0 @@
-# Easy-RSA 3 parameter settings
-
-# NOTE: If you installed Easy-RSA from your distro's package manager, don't edit
-# this file in place -- instead, you should copy the entire easy-rsa directory
-# to another location so future upgrades don't wipe out your changes.
-
-# HOW TO USE THIS FILE
-#
-# vars.example contains built-in examples to Easy-RSA settings. You MUST name
-# this file 'vars' if you want it to be used as a configuration file. If you do
-# not, it WILL NOT be automatically read when you call easyrsa commands.
-#
-# It is not necessary to use this config file unless you wish to change
-# operational defaults. These defaults should be fine for many uses without the
-# need to copy and edit the 'vars' file.
-#
-# All of the editable settings are shown commented and start with the command
-# 'set_var' -- this means any set_var command that is uncommented has been
-# modified by the user. If you're happy with a default, there is no need to
-# define the value to its default.
-
-# NOTES FOR WINDOWS USERS
-#
-# Paths for Windows *MUST* use forward slashes, or optionally double-esscaped
-# backslashes (single forward slashes are recommended.) This means your path to
-# the openssl binary might look like this:
-# "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
-
-# A little housekeeping: DON'T EDIT THIS SECTION
-#
-# Easy-RSA 3.x doesn't source into the environment directly.
-# Complain if a user tries to do this:
-if [ -z "$EASYRSA_CALLER" ]; then
- echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2
- echo "This is no longer necessary and is disallowed. See the section called" >&2
- echo "'How to use this file' near the top comments for more details." >&2
- return 1
-fi
-
-# DO YOUR EDITS BELOW THIS POINT
-
-# This variable should point to the top level of the easy-rsa tree. By default,
-# this is taken to be the directory you are currently in.
-
-set_var EASYRSA "{{ easyrsa_dir }}/easyrsa3/"
-
-# If your OpenSSL command is not in the system PATH, you will need to define the
-# path to it here. Normally this means a full path to the executable, otherwise
-# you could have left it undefined here and the shown default would be used.
-#
-# Windows users, remember to use paths with forward-slashes (or escaped
-# back-slashes.) Windows users should declare the full path to the openssl
-# binary here if it is not in their system PATH.
-
-#set_var EASYRSA_OPENSSL "openssl"
-#
-# This sample is in Windows syntax -- edit it for your path if not using PATH:
-#set_var EASYRSA_OPENSSL "C:/Program Files/OpenSSL-Win32/bin/openssl.exe"
-
-# Edit this variable to point to your soon-to-be-created key directory.
-#
-# WARNING: init-pki will do a rm -rf on this directory so make sure you define
-# it correctly! (Interactive mode will prompt before acting.)
-
-set_var EASYRSA_PKI "$EASYRSA/pki"
-
-# Define X509 DN mode.
-# This is used to adjust what elements are included in the Subject field as the DN
-# (this is the "Distinguished Name.")
-# Note that in cn_only mode the Organizational fields further below aren't used.
-#
-# Choices are:
-# cn_only - use just a CN value
-# org - use the "traditional" Country/Province/City/Org/OU/email/CN format
-
-set_var EASYRSA_DN "cn_only"
-
-# Organizational fields (used with 'org' mode and ignored in 'cn_only' mode.)
-# These are the default values for fields which will be placed in the
-# certificate. Don't leave any of these fields blank, although interactively
-# you may omit any specific field by typing the "." symbol (not valid for
-# email.)
-
-#set_var EASYRSA_REQ_COUNTRY "US"
-#set_var EASYRSA_REQ_PROVINCE "California"
-#set_var EASYRSA_REQ_CITY "San Francisco"
-#set_var EASYRSA_REQ_ORG "Copyleft Certificate Co"
-#set_var EASYRSA_REQ_EMAIL "me@example.net"
-#set_var EASYRSA_REQ_OU "My Organizational Unit"
-
-# Choose a size in bits for your keypairs. The recommended value is 2048. Using
-# 2048-bit keys is considered more than sufficient for many years into the
-# future. Larger keysizes will slow down TLS negotiation and make key/DH param
-# generation take much longer. Values up to 4096 should be accepted by most
-# software. Only used when the crypto alg is rsa (see below.)
-
-# set_var EASYRSA_KEY_SIZE 2048
-
-# The default crypto mode is rsa; ec can enable elliptic curve support.
-# Note that not all software supports ECC, so use care when enabling it.
-# Choices for crypto alg are: (each in lower-case)
-# * rsa
-# * ec
-
-{% if Win10_Enabled is defined and Win10_Enabled == "Y" %}
-set_var EASYRSA_ALGO rsa
-{% else %}
-set_var EASYRSA_ALGO ec
-{% endif %}
-
-# Define the named curve, used in ec mode only:
-
-set_var EASYRSA_CURVE prime256v1
-
-# In how many days should the root CA key expire?
-
-set_var EASYRSA_CA_EXPIRE {{ easyrsa_ca_expire }}
-
-# In how many days should certificates expire?
-
-set_var EASYRSA_CERT_EXPIRE {{ easyrsa_cert_expire }}
-
-# How many days until the next CRL publish date? Note that the CRL can still be
-# parsed after this timeframe passes. It is only used for an expected next
-# publication date.
-
-#set_var EASYRSA_CRL_DAYS 180
-
-# Support deprecated "Netscape" extensions? (choices "yes" or "no".) The default
-# is "no" to discourage use of deprecated extensions. If you require this
-# feature to use with --ns-cert-type, set this to "yes" here. This support
-# should be replaced with the more modern --remote-cert-tls feature. If you do
-# not use --ns-cert-type in your configs, it is safe (and recommended) to leave
-# this defined to "no". When set to "yes", server-signed certs get the
-# nsCertType=server attribute, and also get any NS_COMMENT defined below in the
-# nsComment field.
-
-#set_var EASYRSA_NS_SUPPORT "no"
-
-# When NS_SUPPORT is set to "yes", this field is added as the nsComment field.
-# Set this blank to omit it. With NS_SUPPORT set to "no" this field is ignored.
-
-#set_var EASYRSA_NS_COMMENT "Easy-RSA Generated Certificate"
-
-# A temp file used to stage cert extensions during signing. The default should
-# be fine for most users; however, some users might want an alternative under a
-# RAM-based FS, such as /dev/shm or /tmp on some systems.
-
-#set_var EASYRSA_TEMP_FILE "$EASYRSA_PKI/extensions.temp"
-
-# !!
-# NOTE: ADVANCED OPTIONS BELOW THIS POINT
-# PLAY WITH THEM AT YOUR OWN RISK
-# !!
-
-# Broken shell command aliases: If you have a largely broken shell that is
-# missing any of these POSIX-required commands used by Easy-RSA, you will need
-# to define an alias to the proper path for the command. The symptom will be
-# some form of a 'command not found' error from your shell. This means your
-# shell is BROKEN, but you can hack around it here if you really need. These
-# shown values are not defaults: it is up to you to know what you're doing if
-# you touch these.
-#
-#alias awk="/alt/bin/awk"
-#alias cat="/alt/bin/cat"
-
-# X509 extensions directory:
-# If you want to customize the X509 extensions used, set the directory to look
-# for extensions here. Each cert type you sign must have a matching filename,
-# and an optional file named 'COMMON' is included first when present. Note that
-# when undefined here, default behaviour is to look in $EASYRSA_PKI first, then
-# fallback to $EASYRSA for the 'x509-types' dir. You may override this
-# detection with an explicit dir here.
-#
-#set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types"
-
-# OpenSSL config file:
-# If you need to use a specific openssl config file, you can reference it here.
-# Normally this file is auto-detected from a file named openssl-1.0.cnf from the
-# EASYRSA_PKI or EASYRSA dir (in that order.) NOTE that this file is Easy-RSA
-# specific and you cannot just use a standard config file, so this is an
-# advanced feature.
-
-set_var EASYRSA_SSL_CONF "$EASYRSA/openssl-1.0.cnf"
-
-# Default CN:
-# This is best left alone. Interactively you will set this manually, and BATCH
-# callers are expected to set this themselves.
-
-set_var EASYRSA_REQ_CN "{{ IP_subject_alt_name }}"
-
-# Cryptographic digest to use.
-# Do not change this default unless you understand the security implications.
-# Valid choices include: md5, sha1, sha256, sha224, sha384, sha512
-
-#set_var EASYRSA_DIGEST "sha256"
-
-# Batch mode. Leave this disabled unless you intend to call Easy-RSA explicitly
-# in batch mode without any user input, confirmation on dangerous operations,
-# or most output. Setting this to any non-blank string enables batch mode.
-
-set_var EASYRSA_BATCH "{{ IP_subject_alt_name }}"
diff --git a/roles/vpn/templates/mobileconfig.j2 b/roles/vpn/templates/mobileconfig.j2
index d287326..9ee20c4 100644
--- a/roles/vpn/templates/mobileconfig.j2
+++ b/roles/vpn/templates/mobileconfig.j2
@@ -172,7 +172,7 @@
ca.crt
PayloadContent
- {{ PayloadContentCA.stdout }}
+ {{ PayloadContentCA }}
PayloadDescription
Adds a CA root certificate
diff --git a/roles/vpn/templates/openssl.cnf.j2 b/roles/vpn/templates/openssl.cnf.j2
new file mode 100644
index 0000000..415557f
--- /dev/null
+++ b/roles/vpn/templates/openssl.cnf.j2
@@ -0,0 +1,143 @@
+# For use with Easy-RSA 3.0 and OpenSSL 1.0.*
+
+RANDFILE = .rnd
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = . # Where everything is kept
+certs = $dir # Where the issued certs are kept
+crl_dir = $dir # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir/certs # default place for new certs.
+
+certificate = $dir/cacert.pem # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/private/cakey.pem # The private key
+RANDFILE = $dir/private/.rand # private random number file
+
+x509_extensions = basic_exts # The extentions to add to the cert
+
+# This allows a V2 CRL. Ancient browsers don't like it, but anything Easy-RSA
+# is designed for will. In return, we get the Issuer attached to CRLs.
+crl_extensions = crl_ext
+
+default_days = 3650 # how long to certify for
+default_crl_days= 3650 # how long before next CRL
+default_md = sha256 # use public key default MD
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_anything
+
+# For the 'anything' policy, which defines allowed DN fields
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+name = optional
+emailAddress = optional
+
+####################################################################
+# Easy-RSA request handling
+# We key off $DN_MODE to determine how to format the DN
+[ req ]
+default_bits = 2048
+default_keyfile = privkey.pem
+default_md = sha256
+distinguished_name = cn_only
+x509_extensions = easyrsa_ca # The extentions to add to the self signed cert
+
+# A placeholder to handle the $EXTRA_EXTS feature:
+#%EXTRA_EXTS% # Do NOT remove or change this line as $EXTRA_EXTS support requires it
+
+####################################################################
+# Easy-RSA DN (Subject) handling
+
+# Easy-RSA DN for cn_only support:
+[ cn_only ]
+commonName = Common Name (eg: your user, host, or server name)
+commonName_max = 64
+commonName_default = {{ IP_subject_alt_name }}
+
+# Easy-RSA DN for org support:
+[ org ]
+countryName = Country Name (2 letter code)
+countryName_default = US
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = California
+
+localityName = Locality Name (eg, city)
+localityName_default = San Francisco
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = Copyleft Certificate Co
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+organizationalUnitName_default = My Organizational Unit
+
+commonName = Common Name (eg: your user, host, or server name)
+commonName_max = 64
+commonName_default = {{ IP_subject_alt_name }}
+
+emailAddress = Email Address
+emailAddress_default = me@example.net
+emailAddress_max = 64
+
+####################################################################
+# Easy-RSA cert extension handling
+
+# This section is effectively unused as the main script sets extensions
+# dynamically. This core section is left to support the odd usecase where
+# a user calls openssl directly.
+[ basic_exts ]
+basicConstraints = CA:FALSE
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid,issuer:always
+
+extendedKeyUsage = serverAuth,1.3.6.1.5.5.7.3.17
+keyUsage = digitalSignature, keyEncipherment
+subjectAltName = ${ENV::subjectAltName}
+
+# The Easy-RSA CA extensions
+[ easyrsa_ca ]
+
+# PKIX recommendations:
+
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This could be marked critical, but it's nice to support reading by any
+# broken clients who attempt to do so.
+basicConstraints = CA:true
+
+# Limit key usage to CA tasks. If you really want to use the generated pair as
+# a self-signed cert, comment this out.
+keyUsage = cRLSign, keyCertSign
+
+# nsCertType omitted by default. Let's try to let the deprecated stuff die.
+# nsCertType = sslCA
+
+# CRL extensions.
+[ crl_ext ]
+
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
+
+
+
diff --git a/tests/update-users.sh b/tests/update-users.sh
new file mode 100755
index 0000000..b0cbb19
--- /dev/null
+++ b/tests/update-users.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -e
+
+CAPW=`cat /tmp/ca_password`
+
+sed -i 's/- jack$/- jack_test/' config.cfg
+
+ansible-playbook users.yml -e "server_ip=$LXC_IP server_user=root ssh_tunneling_enabled=y IP_subject=$LXC_IP easyrsa_CA_password=$CAPW"
+
+cd configs/$LXC_IP/pki/
+
+if openssl crl -inform pem -noout -text -in crl/jack.crt | grep CRL
+ then
+ echo "The CRL check passed"
+ else
+ echo "The CRL check failed"
+ exit 1
+fi
+
+if openssl x509 -inform pem -noout -text -in certs/jack_test.crt | grep CN=jack_test
+ then
+ echo "The new user exist"
+ else
+ echo "The new user does not exist"
+ exit 1
+fi
diff --git a/users.yml b/users.yml
index b6f7130..c9837a2 100644
--- a/users.yml
+++ b/users.yml
@@ -4,30 +4,6 @@
gather_facts: False
vars_files:
- config.cfg
- vars_prompt:
-
- - name: "server_ip"
- prompt: "Enter IP address of your server: (use localhost for local installation)\n"
- default: localhost
- private: no
-
- - name: "server_user"
- prompt: "What user should we use to login on the server? (ignore if you're deploying to localhost):\n"
- default: "root"
- private: no
-
- - name: "ssh_tunneling_enabled"
- prompt: "Do you want each user to have their own account for SSH tunneling? (y/n):\n"
- default: "n"
- private: no
-
- - name: "IP_subject"
- prompt: "Enter public IP address of your server: (IMPORTANT! This IP is used to verify the certificate)\n"
- private: no
-
- - name: "easyrsa_CA_password"
- prompt: "Enter the password for the private CA key:\n"
- private: yes
tasks:
- name: Add the server to the vpn-host group
@@ -39,6 +15,7 @@
ssh_tunneling_enabled: "{{ ssh_tunneling_enabled }}"
easyrsa_CA_password: "{{ easyrsa_CA_password }}"
IP_subject: "{{ IP_subject }}"
+ ansible_ssh_private_key_file: "{{ SSH_keys.private }}"
- name: Wait until SSH becomes ready...
local_action:
@@ -53,7 +30,7 @@
- name: User management
hosts: vpn-host
- gather_facts: false
+ gather_facts: true
become: true
vars_files:
- config.cfg
@@ -61,6 +38,7 @@
pre_tasks:
- set_fact:
IP_subject_alt_name: "{{ IP_subject }}"
+ easyrsa_p12_export_password: "{{ (ansible_date_time.iso8601_basic|sha1|to_uuid).split('-')[0] }}"
roles:
- { role: ssh_tunneling, tags: [ 'ssh_tunneling' ], when: ssh_tunneling_enabled is defined and ssh_tunneling_enabled == "y" }
@@ -70,73 +48,136 @@
- name: Gather Facts
setup:
- - set_fact:
- easyrsa_p12_export_password: "{{ (ansible_date_time.iso8601_basic|sha1|to_uuid).split('-')[0] }}"
+ - name: Cheking the signature algorithm
+ local_action: >
+ shell openssl x509 -text -in certs/{{ IP_subject_alt_name }}.crt | grep 'Signature Algorithm' | head -n1
+ become: no
+ register: sig_algo
+ args:
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+
+ - name: Change the algorithm to RSA
+ set_fact:
+ algo_params: "rsa:2048"
+ when: '"ecdsa" not in sig_algo.stdout'
- name: Build the client's pair
- shell: >
- ./easyrsa gen-req {{ item }} nopass -- -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" &&
- ./easyrsa --subject-alt-name='DNS:{{ item }}' sign-req client {{ item }} nopass -- -passin pass:"{{ easyrsa_CA_password }}" &&
- touch '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized'
+ local_action: >
+ shell openssl req -utf8 -new -newkey {{ algo_params | default('ec:ecparams/prime256v1.pem') }} -config openssl.cnf -keyout private/{{ item }}.key -out reqs/{{ item }}.req -nodes -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" -batch &&
+ openssl ca -utf8 -in reqs/{{ item }}.req -out certs/{{ item }}.crt -config openssl.cnf -days 3650 -batch -passin pass:"{{ easyrsa_CA_password }}" -subj "/CN={{ item }}" &&
+ touch certs/{{ item }}_crt_generated
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
- creates: '{{ easyrsa_dir }}/easyrsa3/pki/{{ item }}_initialized'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: certs/{{ item }}_crt_generated
+ environment:
+ subjectAltName: "DNS:{{ item }}"
with_items: "{{ users }}"
- name: Build the client's p12
- shell: >
- openssl pkcs12 -in {{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt -inkey {{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.key -export -name {{ item }} -out /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 -certfile {{ easyrsa_dir }}/easyrsa3//pki/ca.crt -passout pass:{{ easyrsa_p12_export_password }}
+ local_action: >
+ shell openssl pkcs12 -in certs/{{ item }}.crt -inkey private/{{ item }}.key -export -name {{ item }} -out private/{{ item }}.p12 -certfile cacert.pem -passout pass:"{{ easyrsa_p12_export_password }}"
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
with_items: "{{ users }}"
+ - name: Copy the p12 certificates
+ local_action:
+ module: copy
+ src: "configs/{{ IP_subject_alt_name }}/pki/private/{{ item }}.p12"
+ dest: "configs/{{ IP_subject_alt_name }}/{{ item }}.p12"
+ mode: 0600
+ become: no
+ with_items:
+ - "{{ users }}"
+
- name: Get active users
- shell: >
- grep ^V pki/index.txt | grep -v "{{ IP_subject_alt_name }}" | awk '{print $5}' | sed 's/\/CN=//g'
+ local_action: >
+ shell grep ^V index.txt | grep -v "{{ IP_subject_alt_name }}" | awk '{print $5}' | sed 's/\/CN=//g'
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
register: valid_certs
- name: Revoke non-existing users
- shell: >
- openssl ec -in pki/private/ca.key -out pki/private/ca.key -passin pass:"{{ easyrsa_CA_password }}" -passout pass:"" &&
- ipsec pki --signcrl --cacert {{ easyrsa_dir }}/easyrsa3//pki/ca.crt --cakey {{ easyrsa_dir }}/easyrsa3/pki/private/ca.key --reason superseded --cert {{ easyrsa_dir }}/easyrsa3//pki/issued/{{ item }}.crt > /etc/ipsec.d/crls/{{ item }}.der &&
- ./easyrsa revoke {{ item }} &&
- openssl ec -aes256 -in pki/private/ca.key -out pki/private/ca.key -passin pass:"" -passout pass:"{{ easyrsa_CA_password }}" &&
- ipsec rereadcrls
+ local_action: >
+ shell openssl ca -config openssl.cnf -passin pass:"{{ easyrsa_CA_password }}" -revoke certs/{{ item }}.crt &&
+ openssl ca -gencrl -config openssl.cnf -passin pass:"{{ easyrsa_CA_password }}" -revoke certs/{{ item }}.crt -out crl/{{ item }}.crt
+ touch crl/{{ item }}_revoked
+ become: no
args:
- chdir: '{{ easyrsa_dir }}/easyrsa3/'
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
+ creates: crl/{{ item }}_revoked
+ environment:
+ subjectAltName: "DNS:{{ item }}"
when: item not in users
with_items: "{{ valid_certs.stdout_lines }}"
+ - name: Copy the revoked certificates to the vpn server
+ copy:
+ src: configs/{{ IP_subject_alt_name }}/pki/crl/{{ item }}.crt
+ dest: /etc/ipsec.d/crls/{{ item }}.crt
+ when: item not in users
+ with_items: "{{ valid_certs.stdout_lines }}"
+ notify:
+ - rereadcrls
+
- name: Register p12 PayloadContent
- shell: >
- cat /{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 | base64
+ local_action: >
+ shell cat private/{{ item }}.p12 | base64
register: PayloadContent
+ become: no
+ args:
+ chdir: "configs/{{ IP_subject_alt_name }}/pki/"
with_items: "{{ users }}"
- - name: Register CA PayloadContent
- shell: >
- cat /{{ easyrsa_dir }}/easyrsa3/pki/ca.crt | base64
- register: PayloadContentCA
+ - name: Set facts for mobileconfigs
+ set_fact:
+ proxy_enabled: false
+ PayloadContentCA: "{{ lookup('file' , 'configs/{{ IP_subject_alt_name }}/pki/cacert.pem')|b64encode }}"
- name: Build the mobileconfigs
- template: src=roles/vpn/templates/mobileconfig.j2 dest=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item.0 }}.mobileconfig mode=0600
+ local_action:
+ module: template
+ src: roles/vpn/templates/mobileconfig.j2
+ dest: configs/{{ IP_subject_alt_name }}/{{ item.0 }}.mobileconfig
+ mode: 0600
+ become: no
with_together:
- "{{ users }}"
- "{{ PayloadContent.results }}"
no_log: True
- - name: Fetch users P12
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.p12 dest=configs/{{ IP_subject_alt_name }}_{{ item }}.p12 flat=yes
- with_items: "{{ users }}"
+ - name: Build the client ipsec config file
+ local_action:
+ module: template
+ src: roles/vpn/templates/client_ipsec.conf.j2
+ dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.conf
+ mode: 0600
+ become: no
+ with_items:
+ - "{{ users }}"
- - name: Fetch users mobileconfig
- fetch: src=/{{ easyrsa_dir }}/easyrsa3//pki/private/{{ item }}.mobileconfig dest=configs/{{ IP_subject_alt_name }}_{{ item }}.mobileconfig flat=yes
- with_items: "{{ users }}"
+ - name: Build the client ipsec secret file
+ local_action:
+ module: template
+ src: roles/vpn/templates/client_ipsec.secrets.j2
+ dest: configs/{{ IP_subject_alt_name }}/ipsec_{{ item }}.secrets
+ mode: 0600
+ become: no
+ with_items:
+ - "{{ users }}"
- - name: Fetch server CA certificate
- fetch: src=/{{ easyrsa_dir }}/easyrsa3/pki/ca.crt dest=configs/{{ IP_subject_alt_name }}_ca.crt flat=yes
+ - name: Build the windows client powershell script
+ local_action:
+ module: template
+ src: roles/vpn/templates/client_windows.ps1.j2
+ dest: configs/{{ IP_subject_alt_name }}/windows_{{ item }}.ps1
+ mode: 0600
+ become: no
+ when: Win10_Enabled is defined and Win10_Enabled == "Y"
+ with_items: "{{ users }}"
# SSH
@@ -163,3 +204,7 @@
post_tasks:
- debug: msg="{{ congrats.split('\n') }}"
tags: always
+
+ handlers:
+ - name: rereadcrls
+ shell: ipsec rereadcrls