summaryrefslogtreecommitdiff
path: root/data/templates/ipsec
diff options
context:
space:
mode:
Diffstat (limited to 'data/templates/ipsec')
-rw-r--r--data/templates/ipsec/charon/dhcp.conf.tmpl11
-rw-r--r--data/templates/ipsec/charon/eap-radius.conf.tmpl115
-rw-r--r--data/templates/ipsec/interfaces_use.conf.tmpl5
-rw-r--r--data/templates/ipsec/ios_profile.tmpl104
-rw-r--r--data/templates/ipsec/ipsec.conf.tmpl6
-rw-r--r--data/templates/ipsec/ipsec.secrets.tmpl10
-rw-r--r--data/templates/ipsec/remote-access.tmpl28
-rw-r--r--data/templates/ipsec/swanctl.conf.tmpl46
-rw-r--r--data/templates/ipsec/swanctl/l2tp.tmpl30
-rw-r--r--data/templates/ipsec/swanctl/peer.tmpl4
-rw-r--r--data/templates/ipsec/swanctl/remote_access.tmpl9
-rw-r--r--data/templates/ipsec/windows_profile.tmpl4
12 files changed, 301 insertions, 71 deletions
diff --git a/data/templates/ipsec/charon/dhcp.conf.tmpl b/data/templates/ipsec/charon/dhcp.conf.tmpl
index 2879550a8..92774b275 100644
--- a/data/templates/ipsec/charon/dhcp.conf.tmpl
+++ b/data/templates/ipsec/charon/dhcp.conf.tmpl
@@ -1,12 +1,11 @@
dhcp {
load = yes
-
-{% if options is defined and options.remote_access is defined and options.remote_access.dhcp_pool is defined %}
-{% if options.remote_access.dhcp_pool.interface is defined %}
- interface = {{ options.remote_access.dhcp_pool.interface }}
+{% if remote_access is defined and remote_access.dhcp is defined %}
+{% if remote_access.dhcp.interface is defined %}
+ interface = {{ remote_access.dhcp.interface }}
{% endif %}
-{% if options.remote_access.dhcp_pool.server is defined %}
- server = {{ options.remote_access.dhcp_pool.server }}
+{% if remote_access.dhcp.server is defined %}
+ server = {{ remote_access.dhcp.server }}
{% endif %}
{% endif %}
diff --git a/data/templates/ipsec/charon/eap-radius.conf.tmpl b/data/templates/ipsec/charon/eap-radius.conf.tmpl
new file mode 100644
index 000000000..5ec35c988
--- /dev/null
+++ b/data/templates/ipsec/charon/eap-radius.conf.tmpl
@@ -0,0 +1,115 @@
+eap-radius {
+ # Send RADIUS accounting information to RADIUS servers.
+ # accounting = no
+
+ # Close the IKE_SA if there is a timeout during interim RADIUS accounting
+ # updates.
+ # accounting_close_on_timeout = yes
+
+ # Interval in seconds for interim RADIUS accounting updates, if not
+ # specified by the RADIUS server in the Access-Accept message.
+ # accounting_interval = 0
+
+ # If enabled, accounting is disabled unless an IKE_SA has at least one
+ # virtual IP. Only for IKEv2, for IKEv1 a virtual IP is strictly necessary.
+ # accounting_requires_vip = no
+
+ # If enabled, adds the Class attributes received in Access-Accept message to
+ # the RADIUS accounting messages.
+ # accounting_send_class = no
+
+ # Use class attributes in Access-Accept messages as group membership
+ # information.
+ # class_group = no
+
+ # Closes all IKE_SAs if communication with the RADIUS server times out. If
+ # it is not set only the current IKE_SA is closed.
+ # close_all_on_timeout = no
+
+ # Send EAP-Start instead of EAP-Identity to start RADIUS conversation.
+ # eap_start = no
+
+ # Use filter_id attribute as group membership information.
+ # filter_id = no
+
+ # Prefix to EAP-Identity, some AAA servers use a IMSI prefix to select the
+ # EAP method.
+ # id_prefix =
+
+ # Whether to load the plugin. Can also be an integer to increase the
+ # priority of this plugin.
+ load = yes
+
+ # NAS-Identifier to include in RADIUS messages.
+ nas_identifier = {{ remote_access.radius.nas_identifier if remote_access is defined and remote_access.radius is defined and remote_access.radius.nas_identifier is defined else 'strongSwan' }}
+
+ # Port of RADIUS server (authentication).
+ # port = 1812
+
+ # Base to use for calculating exponential back off.
+ # retransmit_base = 1.4
+
+ # Timeout in seconds before sending first retransmit.
+ # retransmit_timeout = 2.0
+
+ # Number of times to retransmit a packet before giving up.
+ # retransmit_tries = 4
+
+ # Shared secret between RADIUS and NAS. If set, make sure to adjust the
+ # permissions of the config file accordingly.
+ # secret =
+
+ # IP/Hostname of RADIUS server.
+ # server =
+
+ # Number of sockets (ports) to use, increase for high load.
+ # sockets = 1
+
+ # Whether to include the UDP port in the Called- and Calling-Station-Id
+ # RADIUS attributes.
+ # station_id_with_port = yes
+
+ dae {
+ # Enables support for the Dynamic Authorization Extension (RFC 5176).
+ # enable = no
+
+ # Address to listen for DAE messages from the RADIUS server.
+ # listen = 0.0.0.0
+
+ # Port to listen for DAE requests.
+ # port = 3799
+
+ # Shared secret used to verify/sign DAE messages. If set, make sure to
+ # adjust the permissions of the config file accordingly.
+ # secret =
+ }
+
+ forward {
+ # RADIUS attributes to be forwarded from IKEv2 to RADIUS.
+ # ike_to_radius =
+
+ # Same as ike_to_radius but from RADIUS to IKEv2.
+ # radius_to_ike =
+ }
+
+ # Section to specify multiple RADIUS servers.
+ servers {
+{% if remote_access is defined and remote_access.radius is defined and remote_access.radius.server is defined %}
+{% for server, server_options in remote_access.radius.server.items() if server_options.disable is not defined %}
+ {{ server | replace('.', '-') }} {
+ address = {{ server }}
+ secret = {{ server_options.key }}
+ auth_port = {{ server_options.port }}
+{% if server_options.disable_accounting is not defined %}
+ acct_port = {{ server_options.port | int +1 }}
+{% endif %}
+ sockets = 20
+ }
+{% endfor %}
+{% endif %}
+ }
+
+ # Section to configure multiple XAuth authentication rounds via RADIUS.
+ xauth {
+ }
+}
diff --git a/data/templates/ipsec/interfaces_use.conf.tmpl b/data/templates/ipsec/interfaces_use.conf.tmpl
index 3d285b9be..a77102396 100644
--- a/data/templates/ipsec/interfaces_use.conf.tmpl
+++ b/data/templates/ipsec/interfaces_use.conf.tmpl
@@ -1,6 +1,5 @@
-{% if ipsec_interfaces is defined and 'interface' in ipsec_interfaces %}
-{% set interfaces = ipsec_interfaces['interface'] %}
+{% if interface is defined %}
charon {
- interfaces_use = {{ ', '.join(interfaces) if interfaces is not string else interfaces }}
+ interfaces_use = {{ ', '.join(interface) }}
}
{% endif %} \ No newline at end of file
diff --git a/data/templates/ipsec/ios_profile.tmpl b/data/templates/ipsec/ios_profile.tmpl
new file mode 100644
index 000000000..af6c79d6e
--- /dev/null
+++ b/data/templates/ipsec/ios_profile.tmpl
@@ -0,0 +1,104 @@
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <!-- Set the name to whatever you like, it is used in the profile list on the device -->
+ <key>PayloadDisplayName</key>
+ <string>{{ profile_name }}</string>
+ <!-- This is a reverse-DNS style unique identifier used to detect duplicate profiles -->
+ <key>PayloadIdentifier</key>
+ <string>{{ rfqdn }}</string>
+ <!-- A globally unique identifier, use uuidgen on Linux/Mac OS X to generate it -->
+ <key>PayloadUUID</key>
+ <string>{{ '' | get_uuid }}</string>
+ <key>PayloadType</key>
+ <string>Configuration</string>
+ <key>PayloadVersion</key>
+ <integer>1</integer>
+ <key>PayloadContent</key>
+ <array>
+ <!-- It is possible to add multiple VPN payloads with different identifiers/UUIDs and names -->
+ <dict>
+ <!-- This is an extension of the identifier given above -->
+ <key>PayloadIdentifier</key>
+ <string>{{ rfqdn }}.conf1</string>
+ <!-- A globally unique identifier for this payload -->
+ <key>PayloadUUID</key>
+ <string>{{ '' | get_uuid }}</string>
+ <key>PayloadType</key>
+ <string>com.apple.vpn.managed</string>
+ <key>PayloadVersion</key>
+ <integer>1</integer>
+ <!-- This is the name of the VPN connection as seen in the VPN application later -->
+ <key>UserDefinedName</key>
+ <string>{{ vpn_name }}</string>
+ <key>VPNType</key>
+ <string>IKEv2</string>
+ <key>IKEv2</key>
+ <dict>
+ <!-- Hostname or IP address of the VPN server -->
+ <key>RemoteAddress</key>
+ <string>{{ remote }}</string>
+ <!-- Remote identity, can be a FQDN, a userFQDN, an IP or (theoretically) a certificate's subject DN. Can't be empty.
+ IMPORTANT: DNs are currently not handled correctly, they are always sent as identities of type FQDN -->
+ <key>RemoteIdentifier</key>
+ <string>{{ authentication.id if authentication.id is defined else 'fooo' }}</string>
+ <!-- Local IKE identity, same restrictions as above. If it is empty the client's IP address will be used -->
+ <key>LocalIdentifier</key>
+ <string></string>
+ <!-- Optional, if it matches the CN of the root CA certificate (not the full subject DN) a certificate request will be sent
+ NOTE: If this is not configured make sure to configure leftsendcert=always on the server, otherwise it won't send its certificate -->
+ <key>ServerCertificateIssuerCommonName</key>
+ <string>{{ ca_cn }}</string>
+ <!-- Optional, the CN or one of the subjectAltNames of the server certificate to verify it, if not set RemoteIdentifier will be used -->
+ <key>ServerCertificateCommonName</key>
+ <string>{{ cert_cn }}</string>
+ <!-- The server is authenticated using a certificate -->
+ <key>AuthenticationMethod</key>
+ <string>Certificate</string>
+ <!-- The client uses EAP to authenticate -->
+ <key>ExtendedAuthEnabled</key>
+ <integer>1</integer>
+ <!-- The next two dictionaries are optional (as are the keys in them), but it is recommended to specify them as the default is to use 3DES.
+ IMPORTANT: Because only one proposal is sent (even if nothing is configured here) it must match the server configuration -->
+ <key>IKESecurityAssociationParameters</key>
+ <dict>
+ <!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2encryptionalgorithm -->
+ <key>EncryptionAlgorithm</key>
+ <string>{{ ike_encryption.encryption }}</string>
+ <!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2integrityalgorithm -->
+ <key>IntegrityAlgorithm</key>
+ <string>{{ ike_encryption.hash }}</string>
+ <!-- @see https://developer.apple.com/documentation/networkextension/nevpnikev2diffiehellmangroup -->
+ <key>DiffieHellmanGroup</key>
+ <integer>{{ ike_encryption.dh_group }}</integer>
+ </dict>
+ <key>ChildSecurityAssociationParameters</key>
+ <dict>
+ <key>EncryptionAlgorithm</key>
+ <string>{{ esp_encryption.encryption }}</string>
+ <key>IntegrityAlgorithm</key>
+ <string>{{ esp_encryption.hash }}</string>
+ <key>DiffieHellmanGroup</key>
+ <integer>{{ ike_encryption.dh_group }}</integer>
+ </dict>
+ </dict>
+ </dict>
+ <!-- This payload is optional but it provides an easy way to install the CA certificate together with the configuration -->
+ <dict>
+ <key>PayloadIdentifier</key>
+ <string>org.example.ca</string>
+ <key>PayloadUUID</key>
+ <string>{{ '' | get_uuid }}</string>
+ <key>PayloadType</key>
+ <string>com.apple.security.root</string>
+ <key>PayloadVersion</key>
+ <integer>1</integer>
+ <!-- This is the Base64 (PEM) encoded CA certificate -->
+ <key>PayloadContent</key>
+ <data>
+ {{ ca_cert }}
+ </data>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/data/templates/ipsec/ipsec.conf.tmpl b/data/templates/ipsec/ipsec.conf.tmpl
index a9ea1aac7..1cb531e76 100644
--- a/data/templates/ipsec/ipsec.conf.tmpl
+++ b/data/templates/ipsec/ipsec.conf.tmpl
@@ -16,9 +16,3 @@ config setup
{% if include_ipsec_conf is defined %}
include {{ include_ipsec_conf }}
{% endif %}
-
-{% if delim_ipsec_l2tp_begin is defined %}
-{{delim_ipsec_l2tp_begin}}
-include {{ipsec_ra_conn_file}}
-{{delim_ipsec_l2tp_end}}
-{% endif %}
diff --git a/data/templates/ipsec/ipsec.secrets.tmpl b/data/templates/ipsec/ipsec.secrets.tmpl
index 43b5fe0d2..057e291ed 100644
--- a/data/templates/ipsec/ipsec.secrets.tmpl
+++ b/data/templates/ipsec/ipsec.secrets.tmpl
@@ -3,13 +3,3 @@
{% if include_ipsec_secrets is defined %}
include {{ include_ipsec_secrets }}
{% endif %}
-
-{% if delim_ipsec_l2tp_begin is defined %}
-{{delim_ipsec_l2tp_begin}}
-{% if ipsec_l2tp_auth_mode == 'pre-shared-secret' %}
-{{outside_addr}} %any : PSK "{{ipsec_l2tp_secret}}"
-{% elif ipsec_l2tp_auth_mode == 'x509' %}
-: RSA {{server_key_file_copied}}
-{% endif %}
-{{delim_ipsec_l2tp_end}}
-{% endif %}
diff --git a/data/templates/ipsec/remote-access.tmpl b/data/templates/ipsec/remote-access.tmpl
deleted file mode 100644
index fae48232f..000000000
--- a/data/templates/ipsec/remote-access.tmpl
+++ /dev/null
@@ -1,28 +0,0 @@
-{{delim_ipsec_l2tp_begin}}
-conn {{ra_conn_name}}
- type=transport
- left={{outside_addr}}
- leftsubnet=%dynamic[/1701]
- rightsubnet=%dynamic
- mark_in=%unique
- auto=add
- ike=aes256-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024!
- dpddelay=15
- dpdtimeout=45
- dpdaction=clear
- esp=aes256-sha1,3des-sha1!
- rekey=no
-{% if ipsec_l2tp_auth_mode == 'pre-shared-secret' %}
- authby=secret
- leftauth=psk
- rightauth=psk
-{% elif ipsec_l2tp_auth_mode == 'x509' %}
- authby=rsasig
- leftrsasigkey=%cert
- rightrsasigkey=%cert
- rightca=%same
- leftcert={{server_cert_file_copied}}
-{% endif %}
- ikelifetime={{ipsec_l2tp_ike_lifetime}}
- keylife={{ipsec_l2tp_lifetime}}
-{{delim_ipsec_l2tp_end}}
diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl
index a6ab73cc2..161f19f95 100644
--- a/data/templates/ipsec/swanctl.conf.tmpl
+++ b/data/templates/ipsec/swanctl.conf.tmpl
@@ -1,4 +1,5 @@
### Autogenerated by vpn_ipsec.py ###
+{% import 'ipsec/swanctl/l2tp.tmpl' as l2tp_tmpl %}
{% import 'ipsec/swanctl/profile.tmpl' as profile_tmpl %}
{% import 'ipsec/swanctl/peer.tmpl' as peer_tmpl %}
{% import 'ipsec/swanctl/remote_access.tmpl' as remote_access_tmpl %}
@@ -14,21 +15,28 @@ connections {
{{ peer_tmpl.conn(peer, peer_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
-{% if remote_access is defined and remote_access is not none %}
-{% for rw, rw_conf in remote_access.items() if rw_conf.disable is not defined %}
+{% if remote_access is defined and remote_access.connection is defined and remote_access.connection is not none %}
+{% for rw, rw_conf in remote_access.connection.items() if rw_conf.disable is not defined %}
{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
+{% if l2tp %}
+{{ l2tp_tmpl.conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) }}
+{% endif %}
}
pools {
-{% if remote_access is defined %}
-{% for ra, ra_conf in remote_access.items() if ra_conf.pool.dhcp_enable is not defined %}
- ra-{{ ra }} {
- addrs = {{ ra_conf.pool.prefix }}
- dns = {{ ra_conf.pool.name_server | join(",") }}
-{% if ra_conf.pool.exclude is defined %}
- split_exclude = {{ ra_conf.pool.exclude | join(",") }}
+{% if remote_access is defined and remote_access.pool is defined and remote_access.pool is not none %}
+{% for pool, pool_config in remote_access.pool.items() %}
+ {{ pool }} {
+{% if pool_config.prefix is defined and pool_config.prefix is not none %}
+ addrs = {{ pool_config.prefix }}
+{% endif %}
+{% if pool_config.name_server is defined and pool_config.name_server is not none %}
+ dns = {{ pool_config.name_server | join(',') }}
+{% endif %}
+{% if pool_config.exclude is defined and pool_config.exclude is not none %}
+ split_exclude = {{ pool_config.exclude | join(',') }}
{% endif %}
}
{% endfor %}
@@ -81,8 +89,8 @@ secrets {
{% endif %}
{% endfor %}
{% endif %}
-{% if remote_access is defined %}
-{% for ra, ra_conf in remote_access.items() if remote_access is defined %}
+{% if remote_access is defined and remote_access.connection is defined and remote_access.connection is not none %}
+{% for ra, ra_conf in remote_access.connection.items() if ra_conf.disable is not defined %}
{% if ra_conf.authentication.server_mode == 'pre-shared-secret' %}
ike_{{ ra }} {
{% if ra_conf.authentication.id is defined %}
@@ -103,5 +111,21 @@ secrets {
{% endif %}
{% endfor %}
{% endif %}
+{% if l2tp %}
+{% if l2tp.authentication.mode == 'pre-shared-secret' %}
+ ike_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ secret = "{{ l2tp.authentication.pre_shared_secret }}"
+ }
+{% elif l2tp.authentication.mode == 'x509' %}
+ private_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ file = {{ l2tp.authentication.x509.certificate }}.pem
+{% if l2tp.authentication.x509.passphrase is defined %}
+ secret = "{{ l2tp.authentication.x509.passphrase }}"
+{% endif %}
+ }
+{% endif %}
+{% endif %}
}
diff --git a/data/templates/ipsec/swanctl/l2tp.tmpl b/data/templates/ipsec/swanctl/l2tp.tmpl
new file mode 100644
index 000000000..2df5c2a4d
--- /dev/null
+++ b/data/templates/ipsec/swanctl/l2tp.tmpl
@@ -0,0 +1,30 @@
+{% macro conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) %}
+{% set l2tp_ike = ike_group[l2tp.ike_group] if l2tp.ike_group is defined else None %}
+{% set l2tp_esp = esp_group[l2tp.esp_group] if l2tp.esp_group is defined else None %}
+ l2tp_remote_access {
+ proposals = {{ l2tp_ike | get_esp_ike_cipher | join(',') if l2tp_ike else l2tp_ike_default }}
+ local_addrs = {{ l2tp_outside_address }}
+ dpd_delay = 15s
+ dpd_timeout = 45s
+ rekey_time = {{ l2tp_ike.lifetime if l2tp_ike else l2tp.ike_lifetime }}s
+ reauth_time = 0
+ local {
+ auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
+{% if l2tp.authentication.mode == 'x509' %}
+ certs = {{ l2tp.authentication.x509.certificate }}.pem
+{% endif %}
+ }
+ remote {
+ auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
+ }
+ children {
+ l2tp_remote_access_esp {
+ mode = transport
+ esp_proposals = {{ l2tp_esp | get_esp_ike_cipher | join(',') if l2tp_esp else l2tp_esp_default }}
+ life_time = {{ l2tp_esp.lifetime if l2tp_esp else l2tp.lifetime }}s
+ local_ts = dynamic[/1701]
+ remote_ts = dynamic
+ }
+ }
+ }
+{% endmacro %}
diff --git a/data/templates/ipsec/swanctl/peer.tmpl b/data/templates/ipsec/swanctl/peer.tmpl
index 8e46e8892..dd29ea7d4 100644
--- a/data/templates/ipsec/swanctl/peer.tmpl
+++ b/data/templates/ipsec/swanctl/peer.tmpl
@@ -54,7 +54,7 @@
}
children {
{% if peer_conf.vti is defined and peer_conf.vti.bind is defined and peer_conf.tunnel is not defined %}
-{% set vti_esp = esp_group[peer_conf.vti.esp_group] if peer_conf.vti.esp_group is defined else None %}
+{% set vti_esp = esp_group[ peer_conf.vti.esp_group ] if peer_conf.vti.esp_group is defined else esp_group[ peer_conf.default_esp_group ] %}
peer_{{ name }}_vti {
esp_proposals = {{ vti_esp | get_esp_ike_cipher | join(',') }}
local_ts = 0.0.0.0/0,::/0
@@ -86,7 +86,7 @@
{% set remote_port = tunnel_conf.remote.port if tunnel_conf.remote is defined and tunnel_conf.remote.port is defined else '' %}
{% set remote_suffix = '[{0}/{1}]'.format(proto, remote_port) if proto or remote_port else '' %}
peer_{{ name }}_tunnel_{{ tunnel_id }} {
- esp_proposals = {{ esp_group[peer_conf.default_esp_group] | get_esp_ike_cipher | join(',') }}
+ esp_proposals = {{ tunnel_esp | get_esp_ike_cipher | join(',') }}
{% if tunnel_esp.mode is not defined or tunnel_esp.mode == 'tunnel' %}
{% if tunnel_conf.local is defined and tunnel_conf.local.prefix is defined %}
{% set local_prefix = tunnel_conf.local.prefix if 'any' not in tunnel_conf.local.prefix else ['0.0.0.0/0', '::/0'] %}
diff --git a/data/templates/ipsec/swanctl/remote_access.tmpl b/data/templates/ipsec/swanctl/remote_access.tmpl
index 95f2108fb..456842488 100644
--- a/data/templates/ipsec/swanctl/remote_access.tmpl
+++ b/data/templates/ipsec/swanctl/remote_access.tmpl
@@ -10,10 +10,9 @@
send_certreq = no
rekey_time = {{ ike.lifetime }}s
keyingtries = 0
-{% if rw_conf.pool.dhcp_enable is defined %}
- pools = dhcp
-{% else %}
- pools = ra-{{ name }}
+ unique = {{ rw_conf.unique }}
+{% if rw_conf.pool is defined and rw_conf.pool is not none %}
+ pools = {{ rw_conf.pool | join(',') }}
{% endif %}
local {
{% if rw_conf.authentication.id is defined and rw_conf.authentication.use_x509_id is not defined %}
@@ -34,7 +33,7 @@
}
children {
ikev2-vpn {
- esp_proposals = {{ esp | get_esp_ike_cipher | join(',') }}
+ esp_proposals = {{ esp | get_esp_ike_cipher | join(',') }}
rekey_time = {{ esp.lifetime }}s
rand_time = 540s
dpd_action = clear
diff --git a/data/templates/ipsec/windows_profile.tmpl b/data/templates/ipsec/windows_profile.tmpl
new file mode 100644
index 000000000..8c26944be
--- /dev/null
+++ b/data/templates/ipsec/windows_profile.tmpl
@@ -0,0 +1,4 @@
+Remove-VpnConnection -Name "{{ vpn_name }}" -Force -PassThru
+
+Add-VpnConnection -Name "{{ vpn_name }}" -ServerAddress "{{ remote }}" -TunnelType "Ikev2"
+Set-VpnConnectionIPsecConfiguration -ConnectionName "{{ vpn_name }}" -AuthenticationTransformConstants {{ ike_encryption.encryption }} -CipherTransformConstants {{ ike_encryption.encryption }} -EncryptionMethod {{ esp_encryption.encryption }} -IntegrityCheckMethod {{ esp_encryption.hash }} -PfsGroup None -DHGroup "Group{{ ike_encryption.dh_group }}" -PassThru -Force