Setup of DMVPN on Alpine linux: Difference between revisions

From Alpine Linux
(update cgit link to gitlab)
 
(84 intermediate revisions by 3 users not shown)
Line 12: Line 12:
       post-down ip tunnel del $IFACE || true</nowiki>
       post-down ip tunnel del $IFACE || true</nowiki>
}}
}}
{{TOC right}}


{{note| In conjunction with IPsec VPNs this allows passing of routing information between connected networks.}}
{{note| In conjunction with IPsec VPNs this allows passing of routing information between connected networks.}}
{{note| A standard GRE tunnel will specify its start and endpoint. In case of the mGRE tunnel we do not assign an endpoint, and we provide it an ip address.}}
{{note| A standard GRE tunnel will specify its start and endpoint. In case of the mGRE tunnel we do not assign an start/endpoint, it will dynamically be manage by NHRP}}
{{note|A tunnel key is a 32-bit number is assigned to both ends of the tunnel. A key is added with the add gre tunnel command, and can be modified or deleted with the set gre tunnel command. The tunnel key provides a weak form of security because packets injected into the tunnel by an external party are rejected unless they contain the correct tunnel key value. The key also allows packets to travel through specific tunnels in multi-point networks because the key identifies each end of one tunnel.}}
{{note|A tunnel key is a 32-bit number is assigned to both ends of the tunnel. A key is added with the add gre tunnel command, and can be modified or deleted with the set gre tunnel command. The tunnel key provides a weak form of security because packets injected into the tunnel by an external party are rejected unless they contain the correct tunnel key value. The key also allows packets to travel through specific tunnels in multi-point networks because the key identifies each end of one tunnel.}}


== Setting up IPSec VPN ==
== Setting up IPSec VPN ==


To encrypt the traffic going over this tunnel, we will use ipsec. for ipsec we will use strongswan which has the vici plugin, see:
To encrypt this tunnel, and the traffic in it, we will use strongswan ipsec with its vici plugin.
The vici plugin provides VICI, the Versatile IKE Configuration Interface. As its name indicates, it provides an interface for external applications to not only configure, but also to control and monitor the IKE daemon charon.
The vici plugin provides VICI, the Versatile IKE Configuration Interface. As its name indicates, it provides an interface for external applications to not only configure, but also to control and monitor the IKE daemon charon.
for this we also need a modified version of strongswan, provided by fabled.
for this we also need a modified version of [https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/strongswan Strongswan] which is the default Strongswan in Alpine Linux.


{{cmd|apk add strongswan}}
{{cmd|apk add strongswan}}
=== Template ===
Template taken from other wiki docs.
{{cat|/etc/swanctl/swanctl.conf|<nowiki>connections {
        dmvpn {
                version = 2                        # enable IKEv2
                pull = no                          # IKEv1 only. Push enabled. IKEv2 does not support pull.
                mobike = no                        # disable support for mobile clients tunnel migration
                dpd_delay = 15                      # Interval to check the liveness of a peer if not traffic has passed
                dpd_timeout = 30                    # IKEv1 only
                fragmentation = yes                # NOTE: has recently been added. docs are outdated.
                unique = replace                    # replace connection if it already exists
                rekey_time = 4h                    # rekey is by default already 4h
                reauth_time = 13h                  # re authenticate ipsec tunnel
                proposals = aes256-sha512-ecp384    # docs say default is considered safe and has good interoperability
                local {
                        certs = cert                # certificates used for authentication
                        auth  = pubkey              # a private key associated to a usable certificate
                        id    = spoke1              # IKE identity which should be included in the certificate. ie fqdn
                }
                remote {
                        auth = pubkey              # Authentication to expect from remote
                }
                children {                          # what is the difference between remote and children? local and remote is only to specify authentication?
                        dmvpn {
                                esp_proposals = aes256-sha512-ecp384  # docs say default is considered safe and has good interoperability
                                local_ts = dynamic[gre]              # traffic selectors, dynamic to use outer address of virtual ip. restrict to GRE protocol
                                remote_ts = dynamic[gre]              # traffic selectors, dynamic to use outer address of virtual ip. restrict to GRE protocol
                                inactivity = 90m                      # close CHILD_SA after inactivity
                                rekey_time = 100m                    # Time to schedule CHILD_SA rekeying
                                mode = transport                      # IPsec Mode to establish CHILD_SA with
                                dpd_action = clear                    # default is clear
                                reqid = 1                            # why not use dynamic reqids, allocated incrementally?
                        }
                }
        }
}</nowiki>
}}
{{note|To control the IPSec VPN, NHRP will talk to Strongswan via its vici plugin (Versatile IKE Configuration Interface).}}
{{note|You will need a modified version of Strongswan by fabled which you can find in Alpine Linux Git repository}}
=== Spoke 1 ===


{{cat|/etc/swanctl/swanctl.conf|<nowiki>connections {
{{cat|/etc/swanctl/swanctl.conf|<nowiki>connections {
         dmvpn {
         dmvpn {
                 version = 2
                 version = 2
                pull = no
                 mobike = no
                 mobike = no
                 dpd_delay = 15
                 dpd_delay = 15
                dpd_timeout = 30
                 fragmentation = yes
                 fragmentation = yes
                 unique = replace
                 unique = replace
                rekey_time = 4h
                 reauth_time = 13h
                 reauth_time = 13h
                 proposals = aes256-sha512-ecp384
                 proposals = aes256-sha512-ecp384
                 local {
                 local {
                         auth = psk
                        certs = spoke1.pem
                         id = spoke1
                         auth = pubkey
                         id   = spoke1.vpn.domain.tld
                 }
                 }
                 remote {
                 remote {
                         auth = psk
                         auth = pubkey
                        id  = hub.vpn.domain.tld
                 }
                 }
                 children {
                 children {
Line 52: Line 98:
                                 rekey_time = 100m
                                 rekey_time = 100m
                                 mode = transport
                                 mode = transport
                                dpd_action = clear
                                reqid = 1
                         }
                         }
                 }
                 }
Line 60: Line 104:
}}
}}


{{note|To control the IPSec VPN, NHRP will talk to Strongswan via its vici plugin.}}
=== HUB ===
 
{{cat|/etc/swanctl/swanctl.conf|<nowiki>connections {
        dmvpn {
                version = 2
                mobike = no
                dpd_delay = 15
                fragmentation = yes
                unique = replace
                reauth_time = 13h
                proposals = aes256-sha512-ecp384
                local {
                        certs = spoke1.pem
                        auth  = pubkey
                        id    = hub.vpn.domain.tld
                }
                remote {
                        auth = pubkey
                }
                children {
                        dmvpn {
                                esp_proposals = aes256-sha512-ecp384
                                local_ts = dynamic[gre]
                                remote_ts = dynamic[gre]
                                inactivity = 90m
                                rekey_time = 100m
                                mode = transport
                        }
                }
        }
}</nowiki>
}}


== Generate PKI certificates ==
== Generate PKI certificates ==
{{tip|The ipsec pki command suite allows you to run a simple public key infrastructure. Generate RSA and ECDSA public key pairs, create PKCS#10 certificate requests containing subjectAltNames, create X.509 self-signed end entity and root CA certificates, issue end entity and intermediate CA certificates signed by the private key of a CA and containing subjectAltNames, CRL distribution points and URIs of OCSP servers. You can also extract raw public keys from private keys, certificate requests and certificates and compute two kinds of SHA1-based key IDs.}}


First, generate a private key, the default generates a 2048 bit RSA key
First, generate a private key, the default generates a 2048 bit RSA key
Line 70: Line 147:
Now self-sign a CA certificate using the generated key:
Now self-sign a CA certificate using the generated key:


{{cmd|ipsec pki --self --in caKey.der --dn "C=CH, O=strongSwan, CN=strongSwan CA" --ca > caCert.der}}
{{cmd|<nowiki>ipsec pki --self --in caKey.der --dn "C=CH, O=strongSwan, CN=strongSwan CA" --ca > caCert.der</nowiki>}}


Adjust the distinguished name (DN) to your needs, it will be included in all issued certificates.
Adjust the distinguished name (DN) to your needs, it will be included in all issued certificates.
Line 76: Line 153:
For each peer, i.e. for all VPN clients and VPN gateways in your network, generate an individual private key and issue a matching certificate using your new CA:
For each peer, i.e. for all VPN clients and VPN gateways in your network, generate an individual private key and issue a matching certificate using your new CA:


{{cmd|ipsec pki --gen > peerKey.der
{{cmd|<nowiki>ipsec pki --gen > peerKey.der
ipsec pki --pub --in peerKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der \
ipsec pki --pub --in peerKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der --san host.vpn.example.tld --dn "C=CH, O=strongSwan, CN=peer" > peerCert.der</nowiki>}}
                                            --dn "C=CH, O=strongSwan, CN=peer" > peerCert.der}}


{{note|The second command extracts the public key and issues a certificate using your CA.}}
{{note|The second command extracts the public key and issues a certificate using your CA.}}
{{note|When using id in local/remote config, you will need to add this id to the certificate with --san host.vpn.example.tld}}
==Certificate Revocation Lists (CRL) ==


In case end entity certificates have to be revoked, Certificate Revocation Lists (CRLs) may be generated with the ipsec pki --signcrl command:
In case end entity certificates have to be revoked, Certificate Revocation Lists (CRLs) may be generated with the ipsec pki --signcrl command:
Line 86: Line 165:
{{cmd|ipsec pki --signcrl --cacert caCert.der --cakey caKey.der --reason superseded --cert peerCert.der > crl.der}}
{{cmd|ipsec pki --signcrl --cacert caCert.der --cakey caKey.der --reason superseded --cert peerCert.der > crl.der}}


The certificate given with --cacert must be either a CA certificate or a certificate with the crlSign extended key usage (--flag crlSign).
{{note|The certificate given with --cacert must be either a CA certificate or a certificate with the crlSign extended key usage (--flag crlSign).}}
 
== Install certificates ==
 
On each peer store the following certificates and keys in the /etc/ipsec.d/ subdirectory tree:
 
/etc/swanctl/rsa/hubKey.der holds the private key of the given peer.
/etc/swanctl/x509/hubCert.der holds the end entity certificate of the given peer.
/etc/swanctl/x509ca/caCert.der holds the CA certificate which issued and signed all peer certificates.
 
{{tip|Never store the private key caKey.der of the Certification Authority (CA) on a host with constant direct access to the Internet (e.g. a VPN gateway), since a theft of this master signing key will completely compromise your PKI.}}
 
{{note|Optionally, the CRL may be stored in the following directory (if the certificate contains an URL to a CRL, it will be fetched on demand:
/etc/ipsec.d/crls/crl.der holds the CRL signed by the CA (or a certificate containing the crlSign EKU).}}
 
== Quagga/NHRP ==
 
=== adding the required packages ===
 
{{cmd|apk add iptables quagga-nhrp}}
 
=== Sending Traffic Indication (redirect) notifications ===
 
{{cmd|<nowiki>iptables -A FORWARD -i gre1 -o gre1 \
-m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \
--hashlimit-mode srcip,dstip --hashlimit-srcmask 16 --hashlimit-dstmask 16 \
--hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128</nowiki>}}
 
{{tip|We filter HRHP information from packets and provide them to the NHRP daemon}}
 
===Configuring Quagga===
 
{{note|Quagga needs to be configured with the vty shell. The following parts are split into sections, but all run in the same shell.}}
 
{{cmd|vtysh}}
 
==== General ====
 
configure terminal
log syslog
debug nhrp common
 
==== BGP config ====
 
router bgp 65000
  bgp router-id 172.16.0.1
  bgp deterministic-med
  network 172.16.0.0/16
  redistribute nhrp
  neighbor spokes-ibgp peer-group
  neighbor spokes-ibgp remote-as 65000
  neighbor spokes-ibgp ebgp-multihop 1
  neighbor spokes-ibgp disable-connected-check
  neighbor spokes-ibgp route-reflector-client
  neighbor spokes-ibgp next-hop-self all
  neighbor spokes-ibgp advertisement-interval 1
  neighbor spokes-ibgp soft-reconfiguration inbound
exit
 
==== NHRP config ====
 
interface gre1
  tunnel protection vici profile dmvpn
  tunnel source br0
  ip nhrp network-id 1
  ip nhrp shortcut
  ip nhrp registration no-unique
  ip nhrp nhs dynamic nbma hub1.vpn.domain.tld
  ipv6 nd suppress-ra
  no link-detect
exit
 
==== Save config ====
 
exit
write mem
 
==== Adding spokes to hub ====
 
{{note|For each spoke you are adding, you need to add the gre ip address to the bgp configuration, simillar like above in the config}}
 
{{cmd|vtysh}}


conf terminal
router bgp 65000
  neighbor 172.16.3.1 peer-group spokes-ibgp
exit
write mem


{{tip|Most of the commands used in the vty shell are similar like in Cisco devices. This means you can also gather information from the Cisco docs}}


To talk to the vici interface we use Quagga's new NHRP plugin developed by Timo Teras (fabled).
= See also =
We have to use his modified version, as these changes have not yet been upstreamed.
* [[Dynamic Multipoint VPN (DMVPN)]]
* [[Dynamic Multipoint VPN (DMVPN) Phase 3 with Quagga NHRPd]]


NHRP will automatically create GRE tunnels over IPsec, and we will use BGP to router the traffic over it.
[[category: VPN]]

Latest revision as of 21:05, 25 August 2023

Setting up mGRE tunnel

We start by adding mGRE tunnels to our network configuration.

Contents of /etc/networking/interfaces

... auto gre1 iface gre1 inet static pre-up ip tunnel add $IFACE mode gre key 42 ttl 64 dev br0 || true address 192.168.148.2 netmask 255.255.255.255 post-down ip tunnel del $IFACE || true
Note: In conjunction with IPsec VPNs this allows passing of routing information between connected networks.
Note: A standard GRE tunnel will specify its start and endpoint. In case of the mGRE tunnel we do not assign an start/endpoint, it will dynamically be manage by NHRP
Note: A tunnel key is a 32-bit number is assigned to both ends of the tunnel. A key is added with the add gre tunnel command, and can be modified or deleted with the set gre tunnel command. The tunnel key provides a weak form of security because packets injected into the tunnel by an external party are rejected unless they contain the correct tunnel key value. The key also allows packets to travel through specific tunnels in multi-point networks because the key identifies each end of one tunnel.

Setting up IPSec VPN

To encrypt this tunnel, and the traffic in it, we will use strongswan ipsec with its vici plugin. The vici plugin provides VICI, the Versatile IKE Configuration Interface. As its name indicates, it provides an interface for external applications to not only configure, but also to control and monitor the IKE daemon charon. for this we also need a modified version of Strongswan which is the default Strongswan in Alpine Linux.

apk add strongswan

Template

Template taken from other wiki docs.

Contents of /etc/swanctl/swanctl.conf

connections { dmvpn { version = 2 # enable IKEv2 pull = no # IKEv1 only. Push enabled. IKEv2 does not support pull. mobike = no # disable support for mobile clients tunnel migration dpd_delay = 15 # Interval to check the liveness of a peer if not traffic has passed dpd_timeout = 30 # IKEv1 only fragmentation = yes # NOTE: has recently been added. docs are outdated. unique = replace # replace connection if it already exists rekey_time = 4h # rekey is by default already 4h reauth_time = 13h # re authenticate ipsec tunnel proposals = aes256-sha512-ecp384 # docs say default is considered safe and has good interoperability local { certs = cert # certificates used for authentication auth = pubkey # a private key associated to a usable certificate id = spoke1 # IKE identity which should be included in the certificate. ie fqdn } remote { auth = pubkey # Authentication to expect from remote } children { # what is the difference between remote and children? local and remote is only to specify authentication? dmvpn { esp_proposals = aes256-sha512-ecp384 # docs say default is considered safe and has good interoperability local_ts = dynamic[gre] # traffic selectors, dynamic to use outer address of virtual ip. restrict to GRE protocol remote_ts = dynamic[gre] # traffic selectors, dynamic to use outer address of virtual ip. restrict to GRE protocol inactivity = 90m # close CHILD_SA after inactivity rekey_time = 100m # Time to schedule CHILD_SA rekeying mode = transport # IPsec Mode to establish CHILD_SA with dpd_action = clear # default is clear reqid = 1 # why not use dynamic reqids, allocated incrementally? } } } }
Note: To control the IPSec VPN, NHRP will talk to Strongswan via its vici plugin (Versatile IKE Configuration Interface).
Note: You will need a modified version of Strongswan by fabled which you can find in Alpine Linux Git repository

Spoke 1

Contents of /etc/swanctl/swanctl.conf

connections { dmvpn { version = 2 mobike = no dpd_delay = 15 fragmentation = yes unique = replace reauth_time = 13h proposals = aes256-sha512-ecp384 local { certs = spoke1.pem auth = pubkey id = spoke1.vpn.domain.tld } remote { auth = pubkey id = hub.vpn.domain.tld } children { dmvpn { esp_proposals = aes256-sha512-ecp384 local_ts = dynamic[gre] remote_ts = dynamic[gre] inactivity = 90m rekey_time = 100m mode = transport } } } }

HUB

Contents of /etc/swanctl/swanctl.conf

connections { dmvpn { version = 2 mobike = no dpd_delay = 15 fragmentation = yes unique = replace reauth_time = 13h proposals = aes256-sha512-ecp384 local { certs = spoke1.pem auth = pubkey id = hub.vpn.domain.tld } remote { auth = pubkey } children { dmvpn { esp_proposals = aes256-sha512-ecp384 local_ts = dynamic[gre] remote_ts = dynamic[gre] inactivity = 90m rekey_time = 100m mode = transport } } } }

Generate PKI certificates

Tip: The ipsec pki command suite allows you to run a simple public key infrastructure. Generate RSA and ECDSA public key pairs, create PKCS#10 certificate requests containing subjectAltNames, create X.509 self-signed end entity and root CA certificates, issue end entity and intermediate CA certificates signed by the private key of a CA and containing subjectAltNames, CRL distribution points and URIs of OCSP servers. You can also extract raw public keys from private keys, certificate requests and certificates and compute two kinds of SHA1-based key IDs.

First, generate a private key, the default generates a 2048 bit RSA key

ipsec pki --gen > caKey.der

Now self-sign a CA certificate using the generated key:

ipsec pki --self --in caKey.der --dn "C=CH, O=strongSwan, CN=strongSwan CA" --ca > caCert.der

Adjust the distinguished name (DN) to your needs, it will be included in all issued certificates.

For each peer, i.e. for all VPN clients and VPN gateways in your network, generate an individual private key and issue a matching certificate using your new CA:

ipsec pki --gen > peerKey.der ipsec pki --pub --in peerKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der --san host.vpn.example.tld --dn "C=CH, O=strongSwan, CN=peer" > peerCert.der

Note: The second command extracts the public key and issues a certificate using your CA.
Note: When using id in local/remote config, you will need to add this id to the certificate with --san host.vpn.example.tld

Certificate Revocation Lists (CRL)

In case end entity certificates have to be revoked, Certificate Revocation Lists (CRLs) may be generated with the ipsec pki --signcrl command:

ipsec pki --signcrl --cacert caCert.der --cakey caKey.der --reason superseded --cert peerCert.der > crl.der

Note: The certificate given with --cacert must be either a CA certificate or a certificate with the crlSign extended key usage (--flag crlSign).

Install certificates

On each peer store the following certificates and keys in the /etc/ipsec.d/ subdirectory tree:

/etc/swanctl/rsa/hubKey.der holds the private key of the given peer.
/etc/swanctl/x509/hubCert.der holds the end entity certificate of the given peer.
/etc/swanctl/x509ca/caCert.der holds the CA certificate which issued and signed all peer certificates.
Tip: Never store the private key caKey.der of the Certification Authority (CA) on a host with constant direct access to the Internet (e.g. a VPN gateway), since a theft of this master signing key will completely compromise your PKI.
Note: Optionally, the CRL may be stored in the following directory (if the certificate contains an URL to a CRL, it will be fetched on demand: /etc/ipsec.d/crls/crl.der holds the CRL signed by the CA (or a certificate containing the crlSign EKU).

Quagga/NHRP

adding the required packages

apk add iptables quagga-nhrp

Sending Traffic Indication (redirect) notifications

iptables -A FORWARD -i gre1 -o gre1 \ -m hashlimit --hashlimit-upto 4/minute --hashlimit-burst 1 \ --hashlimit-mode srcip,dstip --hashlimit-srcmask 16 --hashlimit-dstmask 16 \ --hashlimit-name loglimit-0 -j NFLOG --nflog-group 1 --nflog-range 128

Tip: We filter HRHP information from packets and provide them to the NHRP daemon

Configuring Quagga

Note: Quagga needs to be configured with the vty shell. The following parts are split into sections, but all run in the same shell.

vtysh

General

configure terminal
log syslog
debug nhrp common

BGP config

router bgp 65000
 bgp router-id 172.16.0.1
 bgp deterministic-med
 network 172.16.0.0/16
 redistribute nhrp
 neighbor spokes-ibgp peer-group
 neighbor spokes-ibgp remote-as 65000
 neighbor spokes-ibgp ebgp-multihop 1
 neighbor spokes-ibgp disable-connected-check
 neighbor spokes-ibgp route-reflector-client
 neighbor spokes-ibgp next-hop-self all
 neighbor spokes-ibgp advertisement-interval 1
 neighbor spokes-ibgp soft-reconfiguration inbound
exit

NHRP config

interface gre1
 tunnel protection vici profile dmvpn
 tunnel source br0
 ip nhrp network-id 1
 ip nhrp shortcut
 ip nhrp registration no-unique
 ip nhrp nhs dynamic nbma hub1.vpn.domain.tld
 ipv6 nd suppress-ra
 no link-detect
exit

Save config

exit
write mem

Adding spokes to hub

Note: For each spoke you are adding, you need to add the gre ip address to the bgp configuration, simillar like above in the config

vtysh

conf terminal
router bgp 65000
 neighbor 172.16.3.1 peer-group spokes-ibgp
exit
write mem
Tip: Most of the commands used in the vty shell are similar like in Cisco devices. This means you can also gather information from the Cisco docs

See also