feat(xo-server-sdn-controller): encryption for private networks (#4441)

This commit is contained in:
BenjiReis 2019-09-17 15:26:19 +02:00 committed by Julien Fontanet
parent dcf55e4385
commit 5c54611d1b
7 changed files with 80 additions and 9 deletions

View File

@ -9,6 +9,7 @@
- [VM/disks] Don't hide disks that are attached to the same VM twice [#4400](https://github.com/vatesfr/xen-orchestra/issues/4400) (PR [#4414](https://github.com/vatesfr/xen-orchestra/pull/4414))
- [VM/console] Add a button to connect to the VM via the local SSH client (PR [#4415](https://github.com/vatesfr/xen-orchestra/pull/4415))
- [SDN Controller] Add possibility to encrypt private networks (PR [#4441](https://github.com/vatesfr/xen-orchestra/pull/4441))
### Bug fixes
@ -28,5 +29,6 @@
>
> Rule of thumb: add packages on top.
- xo-server-sdn-controller v0.3.0
- xo-server v5.50.0
- xo-web v5.50.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -18,7 +18,8 @@ In the network creation view:
- Select a `pool`
- Select `Private network`
- Select an interface on which to create the network's tunnels
- Select the encapsulation: a choice is offered between `GRE` and `VxLAN`, if `VxLAN` is chosen, then port 4789 must be open for UDP traffic on all the network's hosts (see [the requirements](#requirements))
- Select the encapsulation: a choice is offered between `GRE` and `VxLAN`, if `VxLAN` is chosen, then port 4789 must be open for UDP traffic on all the network's hosts (see [the requirements](#vxlan))
- Choose if the network should be encrypted or not (see [the requirements](#encryption) to use encryption)
- Select other `pool`s to add them to the network if desired
- For each added `pool`: select an interface on which to create the tunnels
- Create the network
@ -27,6 +28,7 @@ In the network creation view:
***NB:***
- All hosts in a private network must be able to reach the other hosts' management interface.
> The term management interface is used to indicate the IP-enabled NIC that carries the management traffic.
- Only 1 encrypted GRE network and 1 encrypted VxLAN network per pool can exist at a time due to Open vSwitch limitation.
### Configuration
@ -40,9 +42,19 @@ If none is provided, the plugin will create its own self-signed certificates.
## Requirements
> All requirements are met by running up to date XCP-ng hosts.
>
> On older XCP-ng hosts, or hosts running Citrix Hypervisor, changes might have to be done manually.
### VxLAN
To be able to use `VxLAN`, the following line needs to be added, if not already present, in `/etc/sysconfig/iptables` of all the hosts where `VxLAN` is wanted:
- `-A xapi-INPUT -p udp -m conntrack --ctstate NEW -m udp --dport 4789 -j ACCEPT`
- On XCP-ng prior to 7.6:
- To be able to use `VxLAN`, the following line needs to be added, if not already present, in `/etc/sysconfig/iptables` of all the hosts where `VxLAN` is wanted: `-A xapi-INPUT -p udp -m conntrack --ctstate NEW -m udp --dport 4789 -j ACCEPT`
### Encryption
> Encryption is not available prior to 8.0.
- On XCP-ng 8.0:
- To be able to encrypt the networks, `openvswitch-ipsec` package must be installed on all the hosts:
- `yum install openvswitch-ipsec --enablerepo=xcp-ng-testing`
- `systemctl enable ipsec`
- `systemctl enable openvswitch-ipsec`
- `systemctl start ipsec`
- `systemctl start openvswitch-ipsec`

View File

@ -4,7 +4,7 @@ import NodeOpenssl from 'node-openssl-cert'
import uuidv4 from 'uuid/v4'
import { access, constants, readFile, writeFile } from 'fs'
import { EventEmitter } from 'events'
import { filter, find, forOwn, map, omitBy } from 'lodash'
import { filter, find, forOwn, map, omitBy, sample } from 'lodash'
import { fromCallback, fromEvent } from 'promise-toolbox'
import { join } from 'path'
@ -103,6 +103,14 @@ function updateNetworkOtherConfig(network) {
)
}
// -----------------------------------------------------------------------------
function createPassword() {
const chars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789?!'
return Array.from({ length: 16 }, _ => sample(chars)).join('')
}
// =============================================================================
class SDNController extends EventEmitter {
@ -110,6 +118,7 @@ class SDNController extends EventEmitter {
Attributes on created networks:
- `other_config`:
- `xo:sdn-controller:encapsulation` : encapsulation protocol used for tunneling (either `gre` or `vxlan`)
- `xo:sdn-controller:encrypted` : `true` if the network is encrypted
- `xo:sdn-controller:pif-device` : PIF device on which the tunnels are created, must be physical and have an IP configuration
- `xo:sdn-controller:private-pool-wide`: `true` if the network is created (and so must be managed) by a SDN Controller
- `xo:sdn-controller:vni` : VxLAN Network Identifier,
@ -207,6 +216,7 @@ class SDNController extends EventEmitter {
networkDescription: { type: 'string' },
encapsulation: { type: 'string' },
pifId: { type: 'string' },
encrypted: { type: 'boolean', optional: true },
}
createPrivateNetwork.resolve = {
xoPool: ['poolId', 'pool', ''],
@ -235,6 +245,7 @@ class SDNController extends EventEmitter {
type: 'string',
},
},
encrypted: { type: 'boolean', optional: true },
}
this._unsetApiMethods = this._xo.addApiMethods({
@ -394,6 +405,7 @@ class SDNController extends EventEmitter {
encapsulation,
xoPif,
vni,
encrypted = false,
}) {
const pool = this._xo.getXapiObject(xoPool)
await this._setPoolControllerIfNeeded(pool)
@ -410,6 +422,7 @@ class SDNController extends EventEmitter {
// See: https://citrix.github.io/xenserver-sdk/#network
automatic: 'false',
'xo:sdn-controller:encapsulation': encapsulation,
'xo:sdn-controller:encrypted': encrypted ? 'true' : undefined,
'xo:sdn-controller:pif-device': pif.device,
'xo:sdn-controller:private-pool-wide': 'true',
'xo:sdn-controller:vni': String(vni),
@ -453,6 +466,7 @@ class SDNController extends EventEmitter {
networkDescription,
encapsulation,
xoPifIds,
encrypted = false,
}) {
const uuid = uuidv4()
const crossPoolNetwork = {
@ -481,6 +495,7 @@ class SDNController extends EventEmitter {
encapsulation,
xoPif,
vni,
encrypted,
})
const network = pool.$xapi.getObjectByRef(poolNetwork.network)
@ -1134,6 +1149,11 @@ class SDNController extends EventEmitter {
const encapsulation =
otherConfig['xo:sdn-controller:encapsulation'] ?? 'gre'
const vni = otherConfig['xo:sdn-controller:vni'] ?? '0'
const password =
otherConfig['xo:sdn-controller:encrypted'] === 'true'
? createPassword()
: undefined
try {
await Promise.all([
client.addInterfaceAndPort(
@ -1142,6 +1162,7 @@ class SDNController extends EventEmitter {
centerClient.host.address,
encapsulation,
vni,
password,
centerNetwork.uuid
),
centerClient.addInterfaceAndPort(
@ -1150,6 +1171,7 @@ class SDNController extends EventEmitter {
client.host.address,
encapsulation,
vni,
password,
network.uuid
),
])
@ -1227,6 +1249,12 @@ class SDNController extends EventEmitter {
const encapsulation =
otherConfig['xo:sdn-controller:encapsulation'] ?? 'gre'
const vni = otherConfig['xo:sdn-controller:vni'] ?? '0'
const password =
otherConfig['xo:sdn-controller:encrypted'] === 'true'
? createPassword()
: undefined
let bridgeName
try {
;[bridgeName] = await Promise.all([
@ -1235,14 +1263,16 @@ class SDNController extends EventEmitter {
network.name_label,
starCenterClient.host.address,
encapsulation,
vni
vni,
password
),
starCenterClient.addInterfaceAndPort(
network.uuid,
network.name_label,
hostClient.host.address,
encapsulation,
vni
vni,
password
),
])
} catch (error) {

View File

@ -18,6 +18,7 @@ export class OvsdbClient {
See:
- OVSDB Protocol: https://tools.ietf.org/html/rfc7047
- OVS Tunneling : http://docs.openvswitch.org/en/latest/howto/tunneling/
- OVS IPSEC : http://docs.openvswitch.org/en/latest/howto/ipsec/
Attributes on created OVS ports (corresponds to a XAPI `PIF` or `VIF`):
- `other_config`:
@ -65,6 +66,7 @@ export class OvsdbClient {
remoteAddress,
encapsulation,
key,
password,
remoteNetwork
) {
if (
@ -111,6 +113,10 @@ export class OvsdbClient {
// Add interface and port to the bridge
const options = ['map', [['remote_ip', remoteAddress], ['key', key]]]
if (password !== undefined) {
options[1].push(['psk', password])
}
const otherConfig =
remoteNetwork !== undefined
? ['map', [['xo:sdn-controller:cross-pool', remoteNetwork]]]

View File

@ -1755,6 +1755,9 @@ const messages = {
newNetworkInfo: 'Info',
newNetworkType: 'Type',
newNetworkEncapsulation: 'Encapsulation',
newNetworkEncrypted: 'Encrypted',
encryptionWarning:
'A pool can have 1 encrypted GRE network and 1 encrypted VxLAN network max',
newNetworkSdnControllerTip:
'Private networks work on up-to-date XCP-ng hosts, for other scenarios please see the requirements',
deleteNetwork: 'Delete network',

View File

@ -36,6 +36,7 @@ const EMPTY = {
bondMode: undefined,
description: '',
encapsulation: 'gre',
encrypted: false,
isPrivate: false,
mtu: '',
name: '',
@ -127,6 +128,9 @@ const NewNetwork = decorate([
bonded: isPrivate ? bonded : false,
}
},
toggleEncrypted() {
return { encrypted: !this.state.encrypted }
},
},
computed: {
disableAddPool: ({ networks }, { nPools }) =>
@ -181,6 +185,7 @@ const NewNetwork = decorate([
isPrivate,
description,
encapsulation,
encrypted,
mtu,
name,
networks,
@ -212,6 +217,7 @@ const NewNetwork = decorate([
networkDescription: description,
encapsulation: encapsulation,
xoPifIds: pifIds,
encrypted,
})
})()
: createPrivateNetwork({
@ -220,6 +226,7 @@ const NewNetwork = decorate([
networkDescription: description,
encapsulation: encapsulation,
pifId: pif.id,
encrypted,
})
: createNetwork({
description,
@ -268,6 +275,7 @@ const NewNetwork = decorate([
isPrivate,
description,
encapsulation,
encrypted,
modeOptions,
mtu,
name,
@ -347,6 +355,16 @@ const NewNetwork = decorate([
]}
value={encapsulation}
/>
<Toggle
onChange={effects.toggleEncrypted}
value={encrypted}
/>{' '}
<label>{_('newNetworkEncrypted')}</label>
<div>
<em>
<Icon icon='info' /> {_('encryptionWarning')}
</em>
</div>
<div className='mt-1'>
{state.networks.map(({ pool, pif }, key) => (
<div key={key}>