Difference between revisions of "MikrotTik: OpenVPN"

From Luky-Wiki
Jump to: navigation, search
(Fix name of user in configuration (interface name))
(Setup VPN server and enable it)
Line 359: Line 359:
  
 
=== Setup VPN server and enable it ===
 
=== Setup VPN server and enable it ===
 +
<pre>
 +
/interface ovpn-server server> set auth=sha1 certificate=server.domain.tld cipher=aes256 default-profile=OVPN-server enabled=yes keepalive-timeout=30 mode=ip netmask=24 require-client-certificate=yes
 +
</pre>
 +
 
=== Grant access for VPN clients through firewall ===
 
=== Grant access for VPN clients through firewall ===
  

Revision as of 21:42, 10 October 2013

Attention: this page is work in progress.

I am using OVPN client / server on MikroTik to connect several network/location. This document describe my findings and my way of configuration.

While i was designing my network i found following limitations (features ?) of OVPN implementation:

  • It is not possible to create connection without CA imported in each MikroTik. If "require-client-certificate" is set then also valid certificates for chain for both client and server is required.
  • It is not possible to create "password less" connection. Each connection is authorized by certificate, username and password
  • Only TCP connection as base channel for OVPN is supported by MikroTik (v 6.4)
  • Prior to version 6.4 it was not possible to specify server by FQDN. Only IP address was supported in previous versions of firmware
  • It is required that client address is managed and assigned by OVPN Server. (e.g. it is not possible to set IP on server and client outside of OVPN configuration)

Steps to successfully create OVPN connection:

Generate valid certificates

I used "valid" in name of this section because I get wrongly generated certificates using "pkitool". I am not sure if this was fail of this tool or my fail but right now i am using different way to generate certificate. Maybe in future I'll debug what was wrong with pkitool.

easy-rsa installation

Gentoo users:

emerge app-crypt/easy-rsa

Ubuntu users:

apt-get install easy-rsa

Other users: please try to find easy-rsa using your distributions package manager or download it from GitHub

Prepare CA directory

Ubuntu have additional command to create CA directory. Select empty directory and then use (I selected "ovpn"):

make-cadir ovpn

Gentoo users can use following rsync command:

rsync -av /usr/share/easy-rsa/ ovpn/

On other Linux distribution you should find easy-rsa installation and copy it to desired working directory.

Variables configuration (e.g. "vars")

Before certificates can be generated it is necessary to customize "vars" file inside new ca directory ("ovpn" in this example)

I prefer strict security so i changed key size from 1024 to 2048

export KEY_SIZE=2048

There are details about certificates at end of "vars" file. It is required that you modify it to reflect your settings. For example like this:

export KEY_COUNTRY="SK"
export KEY_PROVINCE="SK"
export KEY_CITY="Bratislava"
export KEY_ORG="My company name"
export KEY_OU="MikroTik OVPN"
export KEY_CN="changeme"
export KEY_NAME="changeme"
export KEY_EMAIL="myself@mydomain.tld"

CN and NAME will be different for each certificate so i left it as "changeme". Easy-rsa will ask to confirm each KEY_* variable during certificate generation, so it is possible to change both values for each certificate.

CA directory cleanup

Even when you are creating certificates for first time it is good practice to call cleanup command. Later if you recreate certificates from scratch this will ensure that you are working in clean CA directory. Inside CA directory execute:

$ . ./vars 
NOTE: If you run ./clean-all, I will be doing a rm -rf on /.../.../ovpn
$ ./clean-all 
$

Generate CA certificate

Note: configuration is loaded as variables in shell environment. If you experiment with configuration then don't forget to overwrite/remove variables from shell. If you are unsure then simply close terminal session and start with clean one. After that start with ". ./vars" command.

$ ./build-ca 
Generating a 2048 bit RSA private key
...........+++
.............+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [SK]:
State or Province Name (full name) [SK]:
Locality Name (eg, city) [Bratislava]:
Organization Name (eg, company) [My company Name]:
Organizational Unit Name (eg, section) [MikroTik OVPN]:
Common Name (eg, your name or your server's hostname) [changeme]:server.domain.tld
Name [changeme]:server.domain.tld
Email Address [myself@mydomain.tld]:
$

I changed server name simply by typing it while tool was asking for it. Other variables are confirmed by hitting return.

Generate Diffie–Hellman

Note 1: This step is necessary only if you are running OpenVPN server also on Linux. If you are running only MikroTik OVPN and OpenVPN clients then you can skip this step.

Note 2: Without proper HW random generator this can take long time. Grab cup of coffee or try to generate some entropy on your machine while DH is genererated.

(output reduced)

$ ./build-dh 
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
...............................
$ 

Generate server certificate

It is important that all certificates under one CA chain have unique Name/Common Name. I need client and server certificate for one machine so I will generate certificates using FQDN for servers and using hostname for clients. This will also help to simply identify type of certificate without tools.

$ ./build-key-server server.domain.tld
Generating a 2048 bit RSA private key
..................................................................................+++
..........+++
writing new private key to 'server.domain.tld.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [SK]:
State or Province Name (full name) [SK]:
Locality Name (eg, city) [Bratislava]:
Organization Name (eg, company) [My company Name]:
Organizational Unit Name (eg, section) [MikroTik OVPN]:
Common Name (eg, your name or your server's hostname) [server.domain.tld]:
Name [changeme]:server.domain.tld
Email Address [myself@mydomain.tld]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /home/lukas/Desktop/a/ovpn/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'SK'
stateOrProvinceName   :PRINTABLE:'SK'
localityName          :PRINTABLE:'Bratislava'
organizationName      :PRINTABLE:'My company Name'
organizationalUnitName:PRINTABLE:'MikroTik OVPN'
commonName            :PRINTABLE:'server.domain.tld'
name                  :PRINTABLE:'server.domain.tld'
emailAddress          :IA5STRING:'myself@mydomain.tld'
Certificate is to be certified until Oct  4 18:10:34 2023 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
$ 

Again Name/Common Name should be changed from "changeme" to something useful.

Note: Watch if database was successfully updated and certificate signed (last lines of output). It will prevent you from receiving strange errors later.

Generate client certificate

Client certificate is generated in same way as server:

$ ./build-key client
Generating a 2048 bit RSA private key
.............................................+++
.+++
writing new private key to 'client.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [SK]:
State or Province Name (full name) [SK]:
Locality Name (eg, city) [Bratislava]:
Organization Name (eg, company) [My company Name]:
Organizational Unit Name (eg, section) [MikroTik OVPN]:
Common Name (eg, your name or your server's hostname) [client]:
Name [changeme]:client
Email Address [myself@mydomain.tld]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /home/lukas/Desktop/a/ovpn/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'SK'
stateOrProvinceName   :PRINTABLE:'SK'
localityName          :PRINTABLE:'Bratislava'
organizationName      :PRINTABLE:'My company Name'
organizationalUnitName:PRINTABLE:'MikroTik OVPN'
commonName            :PRINTABLE:'client'
name                  :PRINTABLE:'client'
emailAddress          :IA5STRING:'myself@mydomain.tld'
Certificate is to be certified until Oct  4 18:55:35 2023 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
$ 

Note: Watch if database was successfully updated and certificate signed (last lines of output). It will prevent you from receiving strange errors later.

Content of CA directory

ca.key - private CA Certificate key. Keep this file in safe

ca.crt - CA Certificate key.

server.domain.tld.crt
server.domain.tld.key - public and private key for OVPN server

client.crt
client.key - public and private key for OVPN client

dh2048.pem - Diffie–Hellman key for OpenVPN server on Linux

Note: "public" is only name of role. All files should be handled with care and keep in safe. To keep overall integrity of network it is good practice to follow these rules:

  • ca.key is key used to generate all other keys. Protect it in most possible paranoid level. If necessary then store and access it on separate computer with no access to network of any kind
  • protect ca.key with strong password and also all other keys if necessary
  • upload only required keys to each device (e.g. don't upload all of them to each device)

For me my VPN network is important so I'll generate all keys in memory (in /dev/shm or other FS mounted as tmpfs). During this operation I'll disable swap and after I generate all required key's I'll destroy ca.key. Keys are small but there is still possibility that they will be swapped out by kernel. Trace of them can remain on system for some time if they was stored in swap even if keys are removed on OS level.

OVPN Common configuration

Time / Date

First of all don't try to synchronize time over VPN connection. Most of the MikroTik RouterBoard devices don't have RTC (real time clock) and depend on NTP. If you try to synchronize time over VPN then you end up with chicken / egg problem. For successful VPN connection correct time is necessary but you can't synchronize time because VPN connection is not running. Please note that MikroTik is ignoring time source with LI_ALARM set. If your NTP source was restarted recently then it will take a moment to synchronize time.

Select time source reachable without VPN and set it using following command. I am using my own NTP server, so for me Secondary NTP is optional. If You don't have NTP server then select two reliable in different location (for locations in Slovakia I am configuring Primary as stratum 1 NTP server in Bratislava and Secondary of same stratum in Prague)

/system ntp client
set enabled=yes mode=unicast primary-ntp=<IP> secondary-ntp=<IP>

Firewall rules

Network interfaces for VPN connection are not present on system all the time due to way how RouterOS handle VPN connection. In case of problem VPN interface disappear, IP address is deconfigured and VPN traffic can hit default gateway. Even if the connection can't be established with such a condition it is security risk. I don't accept that my internal traffic can go outside of my network. To prevent VPN traffic going unencrypted to default gateway I added following rule to each device acting as gateway for some network (i am using 10.0.0.0/8 network for internal IP allocation and in this particular example "eth10-wan" is my "out" interface to internet. You should modify it to reflect your network configuration)

/ip firewall filter
add action=reject chain=forward dst-address=10.0.0.0/8 out-interface=eth10-wan

Note: for security purpose this rule should be first in firewall configuration. e.g. it is evaluated at first for each packet.

On other hand it is good practice to have similar rule in firewall. In case of problem with connection well explainable ICMP message is returned:

 $ ping -c 3 10.10.10.10
PING 10.10.10.10 (10.10.10.10) 56(84) bytes of data.
From 10.1.1.1: icmp_seq=1 Destination Net Unreachable
From 10.1.1.1: icmp_seq=2 Destination Net Unreachable
From 10.1.1.1: icmp_seq=3 Destination Net Unreachable

--- 10.10.10.10 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 1999ms
$

OVPN Server configuration

Import certificates

To MikroTik with role server upload ca.crt, server.domain.tld.crt and server.domain.tld.key. Import them using following commands:

[admin@mikrotikA] > /certificate 
[admin@mikrotikA] /certificate> import passphrase="" file-name=ca.crt 
     certificates-imported: 1
     private-keys-imported: 0
            files-imported: 1
       decryption-failures: 0
  keys-with-no-certificate: 0

[admin@mikrotikA] /certificate> import passphrase="" file-name=server.domain.tld.crt 
     certificates-imported: 1
     private-keys-imported: 0
            files-imported: 1
       decryption-failures: 0
  keys-with-no-certificate: 0

[admin@mikrotikA] /certificate> import passphrase="" file-name=server.domain.tld.key 
     certificates-imported: 0
     private-keys-imported: 1
            files-imported: 1
       decryption-failures: 0
  keys-with-no-certificate: 0

[admin@mikrotikA] /certificate> 

Normally certificates get name "certX" where X represent sequential number. For better handling i recommend to rename them. Details chan be checked by /certificate print and then certificates can be renamed using:

[admin@mikrotikA] /certificate> set cert1 name=CA
[admin@mikrotikA] /certificate> set cert2 name=server.domain.tld 

Allow VPN connection to pass through firewall

Each my firewall is configured in way that i start with "drop all" for everything and then add rules for allowed communication. I recommend this approach as unclasified (unknown) traffic is simply dropped. If some connection is required then it should be explicitly defined. VPN connection should be allowed by using this rule (or something similar):

/ip firewall filter
add chain=input comment=OpenVPN dst-port=1194 protocol=tcp

Note: this rule should be placed on reasonable position in firewall rules. Exact position depend on specific implementation. Use move after adding this rule or place it directly on correct position in firewall rule list.

Create VPN profile

MikroTik use little bit specific implementation of profiles. This can be confusing for beginners but it is not so hard to understand it.

There are 3 sources of configuration for connection: - interface default profile - connection specific profile - user specific entry

Some configuration attributes are present on all levels, for example remote IP address. You can specify it per user, per profile or per interface. Some configuration attributes are present only on specific level, for example encryption type. It don't make sense to configure it per user as security should be consistent (and also it is not possible technically).

So first of all we need VPN profile, which will set default for incoming connections.

/ppp profile 

add dns-server=192.168.1.1 local-address=192.168.1.1 only-one=yes \
    use-compression=yes use-encryption=required use-mpls=no \
    use-vj-compression=no name=OVPN-server

Note: Van Jacobson compression is not recommended, so enable it only if you really need it. I would like to test compression of data, so i keep it enabled for this time. As i would like to enforce encryption i set it to "required".

Add VPN user (client)

/ppp secret add password=pass1234 profile=OVPN-server remote-address=192.168.1.2 service=ovpn name=client

Fix name of user in configuration (interface name)

/interface ovpn-server> add user=client name=vpn-client

Setup VPN server and enable it

/interface ovpn-server server> set auth=sha1 certificate=server.domain.tld cipher=aes256 default-profile=OVPN-server enabled=yes keepalive-timeout=30 mode=ip netmask=24 require-client-certificate=yes

Grant access for VPN clients through firewall

OVPN Client configuration

Import certificates

Configure client

Verify connection